<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Firefly</title><description>0xDerick</description><link>https://blog.ithuo.net/</link><language>en</language><templateTheme>Firefly</templateTheme><templateThemeVersion>5.12.31</templateThemeVersion><templateThemeUrl>https://github.com/CuteLeaf/Firefly</templateThemeUrl><lastBuildDate>March 30, 2026 at 11:49:34 AM</lastBuildDate><item><title>打造预测市场的“赛博终端”：Polymarket 实时数据监控系统架构设计</title><link>https://blog.ithuo.net/posts/prddiction-polymarket-alpha-architecture-design/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/prddiction-polymarket-alpha-architecture-design/</guid><pubDate>Tue, 11 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;摘要：随着预测市场（Prediction Markets）的爆发式增长，Polymarket 已成为捕捉全球热点事件概率的链上预言机。但原始的链上数据和订单簿数据充满了噪音。本文将从架构师视角，深入剖析如何构建一个企业级的 Polymarket 数据监控与分析系统——PolyAlpha。我们将探讨如何处理混合交易机制数据、设计实时异常检测引擎，以及如何构建“聪明钱”追踪系统。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;1. 背景与痛点&lt;/h2&gt;
&lt;p&gt;Polymarket 与传统的 Token 交易市场（如 Uniswap 或 Binance）有着本质区别：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;二元期权机制&lt;/strong&gt;：价格代表概率，范围严格限制在 0-1 之间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;混合流动性&lt;/strong&gt;：同时存在 CLOB（中央限价订单簿）和 AMM（自动做市商）流动性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;信息不对称&lt;/strong&gt;：新闻、内幕消息对价格的影响比技术指标更直接。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;痛点&lt;/strong&gt;：普通用户面对成百上千的市场，无法实时捕捉到“突发新闻”导致的价格剧变，也无法分辨是“散户跟风”还是“巨鲸建仓”。我们需要一个系统，能将&lt;strong&gt;数据转化为信号&lt;/strong&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;2. 产品功能定义&lt;/h2&gt;
&lt;p&gt;在设计架构之前，我们先明确 &lt;strong&gt;PolyAlpha&lt;/strong&gt; 的核心功能矩阵：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;🎯 实时异动雷达 (Real-time Anomaly Radar)&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;毫秒级监控 100+ 热门市场的成交量飙升、价格剧烈波动。&lt;/li&gt;
&lt;li&gt;基于多因子模型的“异动评分系统”。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;🐋 聪明钱追踪 (Smart Money Tracker)&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;识别高胜率地址（Smart Money）和巨鲸（Whales）。&lt;/li&gt;
&lt;li&gt;实时推送聪明钱的开仓行为。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;⚖️ 套利与逻辑分析 (Arbitrage &amp;amp; Logic Engine)&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;监控互斥市场（Mutually Exclusive）的概率总和是否偏离 100%。&lt;/li&gt;
&lt;li&gt;发现逻辑相关的市场价差（如“特朗普胜选” vs “共和党胜选”）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;3. 系统总体架构设计&lt;/h2&gt;
&lt;p&gt;为了满足高并发、低延迟和数据一致性的要求，我们采用 &lt;strong&gt;微服务 + 事件驱动&lt;/strong&gt; 的架构。&lt;/p&gt;
&lt;h3&gt;3.1 架构全景图&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;graph TD
    %% ===== 数据源层 =====
    subgraph DS
    DSLabel[&quot;数据源层&quot;]
    PolyAPI[&quot;Polymarket CLOB API\nWebSocket&quot;]
    ChainRPC[&quot;Polygon RPC\nOn-chain Events&quot;]
    GammaAPI[&quot;Gamma API\nMetadata&quot;]
    end

    %% ===== 接入层 =====
    subgraph IN
    INLabel[&quot;数据接入与清洗&quot;]
    WS_Client[&quot;WebSocket Ingestor&quot;]
    Chain_Indexer[&quot;Chain Event Indexer&quot;]
    Metadata_Syncer[&quot;Metadata Syncer&quot;]
    Normalizer[&quot;数据标准化模块&quot;]
    end

    %% ===== 核心处理层 =====
    subgraph PROC
    PROCLabel[&quot;流式计算核心&quot;]
    MQ[&quot;Kafka / Redpanda\n消息队列&quot;]
    StreamEngine[&quot;流式计算引擎\nFlink / Python Rx&quot;]
    AnomalyEngine[&quot;异常检测引擎&quot;]
    WhaleEngine[&quot;地址画像引擎&quot;]
    ArbEngine[&quot;套利计算引擎&quot;]
    end

    %% ===== 存储层 =====
    subgraph STORE
    STORELabel[&quot;多级存储&quot;]
    Redis[&quot;Redis Cluster\n实时热数据/缓存&quot;]
    TimescaleDB[&quot;TimescaleDB\n历史K线/交易流&quot;]
    Postgres[&quot;Postgres\n用户数据/元数据&quot;]
    end

    %% ===== 服务层 =====
    subgraph SVC
    SVCLabel[&quot;API与推送&quot;]
    APIGateway[&quot;API Gateway&quot;]
    WSServer[&quot;WebSocket Server\n前端推送&quot;]
    AlertService[&quot;通知服务\nTelegram/Discord&quot;]
    end

    %% ===== 终端 =====
    subgraph CLIENT
    CLIENTLabel[&quot;终端&quot;]
    WebDashboard[&quot;Web Dashboard&quot;]
    MobileApp[&quot;Mobile App&quot;]
    end

    %% ===== 连接关系 =====
    PolyAPI --&amp;gt; WS_Client
    ChainRPC --&amp;gt; Chain_Indexer
    GammaAPI --&amp;gt; Metadata_Syncer

    WS_Client --&amp;gt; Normalizer
    Chain_Indexer --&amp;gt; Normalizer
    Metadata_Syncer --&amp;gt; Normalizer

    Normalizer --&amp;gt; MQ
    MQ --&amp;gt; StreamEngine

    StreamEngine --&amp;gt; AnomalyEngine
    StreamEngine --&amp;gt; WhaleEngine
    StreamEngine --&amp;gt; ArbEngine

    AnomalyEngine --&amp;gt; Redis
    WhaleEngine --&amp;gt; TimescaleDB
    ArbEngine --&amp;gt; Redis

    Redis --&amp;gt; APIGateway
    TimescaleDB --&amp;gt; APIGateway
    Postgres --&amp;gt; APIGateway

    APIGateway --&amp;gt; WebDashboard
    APIGateway --&amp;gt; MobileApp
    Redis --&amp;gt; WSServer
    WSServer --&amp;gt; WebDashboard
    WSServer --&amp;gt; MobileApp
    AnomalyEngine --&amp;gt; AlertService

    %% 隐藏占位 label 的边框（可选美观）
    style DSLabel fill:none,stroke:none
    style INLabel fill:none,stroke:none
    style PROCLabel fill:none,stroke:none
    style STORELabel fill:none,stroke:none
    style SVCLabel fill:none,stroke:none
    style CLIENTLabel fill:none,stroke:none
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;4. 核心模块实现逻辑&lt;/h2&gt;
&lt;h3&gt;4.1 数据接入层 (Ingestion Layer)&lt;/h3&gt;
&lt;p&gt;这是系统的“眼睛”。Polymarket 的数据具有双重性，我们需要同时处理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CLOB 数据 (Off-chain)&lt;/strong&gt;: 通过 WebSocket 连接 Polymarket 的 Orderbook API。这是最高频的数据，包含每一笔撮合（Match）和挂单（Order）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;链上数据 (On-chain)&lt;/strong&gt;: 监听 Polygon 链上的 CTF (Conditional Token Framework) 合约事件。用于验证真实的资金流转和最终结算状态。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;实现难点与对策&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;断连重连&lt;/strong&gt;：WebSocket 必须具备心跳检测和自动重连机制，重连期间需通过 REST API 补录丢失数据。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据标准化&lt;/strong&gt;：将链上的 &lt;code&gt;Split/Merge&lt;/code&gt; 事件和 CLOB 的 &lt;code&gt;Match&lt;/code&gt; 事件统一转化为标准的 &lt;code&gt;Trade&lt;/code&gt; 结构体。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4.2 流式计算与异常检测 (The &quot;Brain&quot;)&lt;/h3&gt;
&lt;p&gt;这是系统的核心。我们不只是存储数据，而是在数据流经内存时即刻进行分析。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;逻辑流程&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;时间窗口聚合&lt;/strong&gt;：对每个 Market ID 维护一个滑动窗口（例如 5分钟、30分钟）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实时指标计算&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Volume_Delta&lt;/code&gt;: 当前窗口成交量 vs 历史均值。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Price_Velocity&lt;/code&gt;: 价格变化速度（一阶导数）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Buy_Sell_Ratio&lt;/code&gt;: 主动买入 vs 主动卖出比例。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;评分模型 (Scoring Model)&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;系统为每个事件打分（0-100）。&lt;/li&gt;
&lt;li&gt;$Score = w_1 \cdot V_{spike} + w_2 \cdot P_{change} + w_3 \cdot Whale_{flag}$&lt;/li&gt;
&lt;li&gt;如果 &lt;code&gt;Score &amp;gt; Threshold&lt;/code&gt;，立即触发报警，并写入 Redis 的“热门异动”有序集合 (Sorted Set)。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;4.3 聪明钱画像引擎 (Smart Money Profiling)&lt;/h3&gt;
&lt;p&gt;如何区分“运气好”和“真大佬”？我们需要建立地址画像库。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;实现逻辑&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;历史回溯&lt;/strong&gt;：每日定时任务扫描历史结算数据。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;指标计算&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ROI (投资回报率)&lt;/strong&gt;: &lt;code&gt;(总盈利 - 总投入) / 总投入&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Win Rate (胜率)&lt;/strong&gt;: &lt;code&gt;盈利次数 / 总下注次数&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Alpha Score&lt;/strong&gt;: 该地址介入后，价格平均上涨幅度（衡量其对市场的影响力）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;标签系统&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;根据指标将地址打标：&lt;code&gt;Smart_Money&lt;/code&gt;, &lt;code&gt;Whale&lt;/code&gt;, &lt;code&gt;High_Frequency_Bot&lt;/code&gt;, &lt;code&gt;Loser&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实时匹配&lt;/strong&gt;：当实时流中出现 &lt;code&gt;Trade&lt;/code&gt; 事件时，立即查询发送方地址的标签。如果是 &lt;code&gt;Smart_Money&lt;/code&gt;，则该笔交易的权重（Weight）瞬间放大，触发跟单信号。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;4.4 存储策略 (Storage Strategy)&lt;/h3&gt;
&lt;p&gt;为了平衡性能与成本，采用冷热分离策略：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hot Data (Redis)&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;存储实时的排行榜（Top Gainers, Top Volume）。&lt;/li&gt;
&lt;li&gt;存储最近 1 小时的 K 线数据（用于前端快速渲染）。&lt;/li&gt;
&lt;li&gt;存储最新的 50 条异动信号。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Warm/Cold Data (TimescaleDB)&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;基于 PostgreSQL 的时序数据库。&lt;/li&gt;
&lt;li&gt;存储所有的历史 Tick 数据和分钟级 K 线。&lt;/li&gt;
&lt;li&gt;利用 Timescale 的 &lt;code&gt;Continuous Aggregates&lt;/code&gt; 功能，自动计算小时级和天级的统计数据，加速历史查询。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Derick</author></item><item><title>智能协作新范式：构建AI友好的文档体系与工作流</title><link>https://blog.ithuo.net/posts/product-ai-engineering-collaboration/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/product-ai-engineering-collaboration/</guid><pubDate>Wed, 15 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;摘要：当AI需要跨越多个会话完成复杂任务时，成功的秘诀不在于模型能力，而在于精心设计的文档体系和工作流程。本文揭示如何通过标准化的文档结构、上下文传递机制和增量式任务管理，让AI代理在长期项目中保持连贯性和效率。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;一、问题起源：AI的&quot;记忆断层&quot;困境&lt;/h2&gt;
&lt;p&gt;在上一篇文章中，我们讨论了如何与AI协作，通过文档提升AI工程的记忆，这篇文章我们继续深化内容。&lt;/p&gt;
&lt;p&gt;尽管现代AI模型具备强大的单次会话能力，但当任务跨越数小时甚至数天时，它们会在新的上下文窗口中&quot;失忆&quot;。即使是最新的AI大模型，在多次会话后仍会失败，主要表现为两种模式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;过度尝试&lt;/strong&gt;：试图一次性完成整个应用，导致上下文耗尽，留下半成品&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;提前完成&lt;/strong&gt;：看到部分功能已实现，就错误地宣告项目完成&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;graph TD
    A[初始提示] --&amp;gt; B{AI行为模式}
    B --&amp;gt;|过度尝试| C[一次性实现太多功能]
    B --&amp;gt;|提前完成| D[部分功能即宣告完成]
    C --&amp;gt; E[上下文耗尽，留下半成品]
    D --&amp;gt; F[功能不完整，质量低下]
    E --&amp;gt; G[后续会话无法有效继续]
    F --&amp;gt; G
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;二、解决方案框架：四层文档体系&lt;/h2&gt;
&lt;p&gt;成功的AI协作始于文档体系的设计。我们需要一个既服务人类又服务AI的结构化知识库。以下是经过验证的四层架构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;项目根目录/
├── 00-AI-Initialization/           # 初始化层：为AI设置基础环境
│   ├── project-vision.md           # 项目愿景和范围
│   ├── feature-list.json           # 功能清单（关键！）
│   ├── init-environment.sh         # 环境初始化脚本
│   └── ai-role-definition.md       # AI角色和权限定义
├── 01-Standards/                   # 标准层：约束和规范
│   ├── naming-conventions.md       # 命名规范
│   ├── directory-structure.md      # 目录结构规范
│   ├── coding-standards.md         # 代码质量标准
│   └── testing-requirements.md     # 测试要求
├── 02-Implementation/              # 实现层：具体指南
│   ├── module-templates/           # 模块开发模板
│   ├── component-library-guide.md  # 组件库使用指南
│   ├── api-integration-guide.md    # API集成指南
│   └── incremental-development.md  # 增量开发指南
└── 03-Validation/                  # 验证层：质量保障
    ├── code-review-checklist.md    # 代码审查清单
    ├── testing-strategy.md         # 测试策略
    ├── progress-tracking.md        # 进度跟踪规范
    └── acceptance-criteria.md      # 验收标准
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;核心文件详解：feature-list.json&lt;/h3&gt;
&lt;p&gt;这是解决&quot;记忆断层&quot;问题的关键。初始化代理会生成一个结构化的功能清单，防止AI随意修改或过早宣告完成。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;project&quot;: &quot;Web Application&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;features&quot;: [
    {
      &quot;id&quot;: &quot;feature-001&quot;,
      &quot;category&quot;: &quot;functional&quot;,
      &quot;priority&quot;: 1,
      &quot;description&quot;: &quot;User login functionality&quot;,
      &quot;steps&quot;: [
        &quot;Display login form with username and password fields&quot;,
        &quot;Validate input format on client side&quot;,
        &quot;Submit credentials to authentication API&quot;,
        &quot;Handle successful authentication (redirect to dashboard)&quot;,
        &quot;Handle failed authentication (display error message)&quot;,
        &quot;Implement remember me functionality&quot;
      ],
      &quot;passes&quot;: false,
      &quot;last_tested&quot;: &quot;2024-11-29&quot;,
      &quot;test_evidence&quot;: &quot;&quot;
    },
    {
      &quot;id&quot;: &quot;feature-002&quot;,
      &quot;category&quot;: &quot;functional&quot;,
      &quot;priority&quot;: 2,
      &quot;description&quot;: &quot;User profile management&quot;,
      &quot;steps&quot;: [
        &quot;Fetch user profile data from API&quot;,
        &quot;Display profile information in editable form&quot;,
        &quot;Validate form inputs&quot;,
        &quot;Submit profile updates to API&quot;,
        &quot;Display success/failure notifications&quot;
      ],
      &quot;passes&quot;: false,
      &quot;last_tested&quot;: &quot;&quot;,
      &quot;test_evidence&quot;: &quot;&quot;
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;关键设计原则&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用JSON格式（AI不易意外修改结构）&lt;/li&gt;
&lt;li&gt;包含详细步骤（防止模糊理解）&lt;/li&gt;
&lt;li&gt;明确的通过/失败状态（防止过早宣告完成）&lt;/li&gt;
&lt;li&gt;优先级排序（指导任务选择）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;三、AI工作流：三阶段任务循环&lt;/h2&gt;
&lt;p&gt;通过标准化的工作流程，让AI在每次会话中都能高效工作。这个流程分为三个阶段：准备、执行、交接。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;flowchart LR
    A[准备阶段] --&amp;gt; B[执行阶段]
    B --&amp;gt; C[交接阶段]
    C --&amp;gt;|下一次会话| A

    subgraph 准备阶段
        A1[读取进度文件]
        A2[查看git历史]
        A3[运行基础测试]
        A4[选择最高优先级任务]
    end

    subgraph 执行阶段
        B1[实现单一功能]
        B2[编写单元测试]
        B3[端到端验证]
        B4[代码质量检查]
    end

    subgraph 交接阶段
        C1[更新进度文件]
        C2[提交代码变更]
        C3[记录测试结果]
        C4[准备下一任务]
    end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;1. 准备阶段：快速理解上下文&lt;/h3&gt;
&lt;p&gt;每次会话开始时，AI需要快速理解当前状态。这通过标准化的初始化脚本实现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash
# scripts/ai-session-start.sh

echo &quot;🔍 AI Session Starting - $(date)&quot;

# 1. 显示当前目录
echo &quot;📍 Current directory:&quot;
pwd

# 2. 读取进度文件
echo &quot;📖 Reading progress file...&quot;
cat 00-AI-Initialization/claude-progress.txt

# 3. 查看git历史
echo &quot;📈 Recent git commits:&quot;
git log --oneline -5

# 4. 读取功能清单
echo &quot;📋 Reading feature list...&quot;
jq &apos;.features[] | select(.passes == false) | .priority, .description&apos; 00-AI-Initialization/feature-list.json

# 5. 启动开发环境
echo &quot;🚀 Starting development environment...&quot;
./00-AI-Initialization/init-environment.sh

# 6. 运行基础测试
echo &quot;🧪 Running basic sanity tests...&quot;
npm run test:basic

echo &quot;✅ Session initialized. Ready to work.&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;AI标准开场白&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Assistant] I&apos;ll start by getting my bearings and understanding the current state of the project.

[Tool Use] &amp;lt;bash - ./scripts/ai-session-start.sh&amp;gt;

[Assistant] Based on the initialization script output, I can see:
- Current progress: User authentication module 80% complete
- Last commit: &quot;fix(auth): handle token expiration edge cases&quot;
- Pending features:
  1. User profile management (priority: 2)
  2. Password reset functionality (priority: 3)
- Basic tests are passing

I&apos;ll focus on implementing the user profile management feature as it&apos;s the highest priority pending task.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 执行阶段：增量式进展&lt;/h3&gt;
&lt;p&gt;AI被明确指示一次只处理一个功能，并通过严格的验证确保质量：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 02-Implementation/incremental-development.md

## 单一任务原则

**AI必须严格遵守**：
1. 每次会话只处理一个功能特性
2. 优先选择feature-list.json中优先级最高的未完成功能
3. 实现必须通过所有验证步骤才能标记为完成

## 验证步骤（必须全部通过）

### 1. 代码质量验证
- [ ] 通过lint检查（无警告）
- [ ] 通过类型检查（无错误）
- [ ] 代码覆盖率 ≥ 80%
- [ ] 无安全漏洞（npm audit clean）

### 2. 功能验证
- [ ] 单元测试全部通过
- [ ] 集成测试全部通过
- [ ] 端到端测试通过（使用Puppeteer/Cypress）
- [ ] 跨浏览器测试通过（Chrome, Firefox, Safari）

### 3. 人工验证准备
- [ ] 更新文档说明
- [ ] 添加使用示例
- [ ] 准备演示脚本
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 交接阶段：为下一任务铺路&lt;/h3&gt;
&lt;p&gt;会话结束时，AI必须留下清晰的工件供下一代理使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash
# scripts/ai-session-end.sh

echo &quot;🏁 AI Session Ending - $(date)&quot;

# 1. 更新进度文件
echo &quot;📝 Updating progress file...&quot;
cat &amp;lt;&amp;lt;EOL &amp;gt;&amp;gt; 00-AI-Initialization/claude-progress.txt
$(date): Completed feature-002 (User profile management)
- Implemented profile form component
- Added API integration for profile updates
- Added validation logic for form inputs
- All tests passing (coverage: 85%)
EOL

# 2. 更新功能清单
echo &quot;✅ Updating feature list...&quot;
jq &apos;.features[] |= if .id == &quot;feature-002&quot; then .passes = true | .last_tested = &quot;&apos;$(date)&apos;&quot; | .test_evidence = &quot;All unit and E2E tests passed&quot; else . end&apos; 00-AI-Initialization/feature-list.json &amp;gt; temp.json &amp;amp;&amp;amp; mv temp.json 00-AI-Initialization/feature-list.json

# 3. 提交代码
echo &quot;💾 Committing changes...&quot;
git add .
git commit -m &quot;feat(profile): implement user profile management
- Add profile form component
- Integrate profile API service
- Add form validation logic
- Add unit and E2E tests
Ref:#123&quot;
git push origin feature/user-profile

echo &quot;✨ Session completed successfully. Ready for next task.&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;四、验收机制：质量门禁与自动验证&lt;/h2&gt;
&lt;p&gt;防止AI标记未完成功能为&quot;完成&quot;的关键是建立严格的验收机制。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;flowchart TB
    A[AI标记功能为完成] --&amp;gt; B{自动验证}
    B --&amp;gt;|单元测试| C[运行测试套件]
    B --&amp;gt;|代码质量| D[静态代码分析]
    B --&amp;gt;|功能验证| E[端到端测试]
    C --&amp;gt; F{通过?}
    D --&amp;gt; G{通过?}
    E --&amp;gt; H{通过?}
    F --&amp;gt;|否| I[拒绝验收]
    G --&amp;gt;|否| I
    H --&amp;gt;|否| I
    F --&amp;gt;|是| J
    G --&amp;gt;|是| J
    H --&amp;gt;|是| J
    J[更新feature-list.json] --&amp;gt; K[通知人类审核]
    I --&amp;gt; L[AI修复问题]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;自动化验收脚本&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash
# scripts/feature-validation.sh

FEATURE_ID=$1

echo &quot;🔍 Validating feature: $FEATURE_ID&quot;

# 1. 运行单元测试
echo &quot;🧪 Running unit tests...&quot;
npm run test:unit -- --feature=$FEATURE_ID
if [ $? -ne 0 ]; then
    echo &quot;❌ Unit tests failed for $FEATURE_ID&quot;
    exit 1
fi

# 2. 代码质量检查
echo &quot;🧹 Code quality check...&quot;
eslint src/features/$FEATURE_ID --max-warnings=0
if [ $? -ne 0 ]; then
    echo &quot;❌ Code quality issues found for $FEATURE_ID&quot;
    exit 1
fi

# 3. 端到端测试
echo &quot;🌐 End-to-end testing...&quot;
npm run test:e2e -- --spec=features/$FEATURE_ID.feature
if [ $? -ne 0 ]; then
    echo &quot;❌ E2E tests failed for $FEATURE_ID&quot;
    exit 1
fi

# 4. 更新状态
echo &quot;✅ All validation passed for $FEATURE_ID&quot;
jq &quot;.features[] |= if .id == \\&quot;$FEATURE_ID\\&quot; then .passes = true | .last_tested = \\&quot;$(date)\\&quot; else . end&quot; 00-AI-Initialization/feature-list.json &amp;gt; temp.json &amp;amp;&amp;amp; mv temp.json 00-AI-Initialization/feature-list.json

echo &quot;🎉 Feature $FEATURE_ID successfully validated and marked as complete.&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;五、进阶实践：人类-AI协作协议&lt;/h2&gt;
&lt;p&gt;最强大的系统不是纯AI或纯人类，而是两者的协同。我们需要明确的协作协议：&lt;/p&gt;
&lt;h3&gt;责任矩阵&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;任务类型&lt;/th&gt;
&lt;th&gt;AI责任&lt;/th&gt;
&lt;th&gt;人类责任&lt;/th&gt;
&lt;th&gt;交接点&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;功能实现&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;生成基础代码、测试、文档&lt;/td&gt;
&lt;td&gt;代码审查、业务逻辑验证&lt;/td&gt;
&lt;td&gt;PR审查&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;架构决策&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;提供选项和分析&lt;/td&gt;
&lt;td&gt;最终决策、战略规划&lt;/td&gt;
&lt;td&gt;架构评审会&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;问题诊断&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;日志分析、可能原因&lt;/td&gt;
&lt;td&gt;根本原因、业务影响&lt;/td&gt;
&lt;td&gt;问题报告&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;质量保障&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;自动化测试、代码检查&lt;/td&gt;
&lt;td&gt;用户体验、边缘情况&lt;/td&gt;
&lt;td&gt;验收测试&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;知识管理&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;文档生成、更新&lt;/td&gt;
&lt;td&gt;知识审核、经验总结&lt;/td&gt;
&lt;td&gt;文档评审&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;冲突解决机制&lt;/h3&gt;
&lt;p&gt;当AI和人类意见不一致时，遵循以下原则：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 01-Standards/conflict-resolution.md

## 决策原则

1. **安全第一**：涉及安全、隐私、合规的问题，人类决策优先
2. **业务价值优先**：业务影响大的决策，人类主导
3. **技术债务最小化**：避免短期便利导致长期维护成本

## 协作流程

1. **AI提出异议时**：
   - 必须提供具体问题分析
   - 提供2-3个替代方案
   - 说明每个方案的优缺点
   - 推荐最佳方案及理由

2. **人类决策时**：
   - 考虑业务优先级
   - 评估长期维护成本
   - 确保架构一致性
   - 记录决策理由供AI学习

## 示例场景

**人类要求**：跳过单元测试快速实现功能
**AI响应**：
&quot;⚠️ 检测到技术债务风险：跳过单元测试可能导致：
- 未来修改时引入回归bug
- 难以理解代码意图
- 增加维护成本

**替代方案**：
1. **快速测试方案**：生成基础测试用例（2小时），覆盖80%核心场景
2. **分阶段方案**：先实现功能，2天内补全测试
3. **TDD方案**：先写测试，再实现（推荐，但需要4小时）

**推荐**：选择方案2，平衡速度和质量。&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;六、实施路线图：从零开始&lt;/h2&gt;
&lt;h3&gt;阶段1：基础设置&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;创建四层文档结构&lt;/li&gt;
&lt;li&gt;配置自动化脚本&lt;/li&gt;
&lt;li&gt;定义核心功能清单&lt;/li&gt;
&lt;li&gt;设置CI/CD流水线&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;阶段2：第一个功能迭代&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;AI实现一个简单功能&lt;/li&gt;
&lt;li&gt;人类审查和调整流程&lt;/li&gt;
&lt;li&gt;优化文档和脚本&lt;/li&gt;
&lt;li&gt;建立反馈循环&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;阶段3：流程优化（持续迭代）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;分析失败模式&lt;/li&gt;
&lt;li&gt;增强自动化验证&lt;/li&gt;
&lt;li&gt;扩展功能覆盖&lt;/li&gt;
&lt;li&gt;培训团队协作&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;gantt
    title AI协作项目实施路线图
    dateFormat  YYYY-MM-DD
    section 基础设置
    文档结构创建       :done,    des1, 2025-01-01, 1d
    自动化脚本配置      :done,    des2, 2025-01-02, 1d
    CI/CD流水线设置     :active,  des3, 2025-01-03, 2d

    section 第一迭代
    核心功能定义       :         des4, 2025-01-05, 1d
    AI实现与验证       :         des5, 2025-01-06, 2d
    人类审查与优化      :         des6, 2025-01-08, 1d

    section 优化扩展
    流程改进          :         des7, 2025-01-10, 3d
    团队培训          :         des8, 2025-01-13, 2d
    全面推广          :         des9, 2025-01-15, 5d
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;七、结语：AI协作的未来&lt;/h2&gt;
&lt;p&gt;此刻我内心在想：&lt;strong&gt;AI的终极价值不在于它能做什么，而在于它如何被工程化地使用&lt;/strong&gt;。当我们将&quot;AI的尽头是软件工程&quot;这一理念付诸实践时，我们不仅提升了开发效率，也重新定义了人机协作的边界。&lt;/p&gt;
&lt;p&gt;通过精心设计的文档体系、标准化的工作流程和严格的验收机制，我们让AI代理在长期项目中保持连贯性和效率。这不是关于取代人类开发者，而是关于&lt;strong&gt;放大人类创造力&lt;/strong&gt;——让AI处理重复性工作，让人类专注于创新和战略思考。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>让AIAgent交替工作：构建跨会话的高效开发流程</title><link>https://blog.ithuo.net/posts/effective-harnesses-for-long-running-agents/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/effective-harnesses-for-long-running-agents/</guid><pubDate>Fri, 10 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;&lt;strong&gt;当AI技术从实验室走向生产环境时，其成功与否不再取决于模型参数规模或算法精妙程度，而取决于能否融入严谨的软件工程体系&lt;/strong&gt;。&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;p&gt;在使用AI工具开发一个商业软件项目时，无论采用哪种研发模式，每个Agent只能工作一个班次，而且下一班的subagent完全不记得上一班做了什么。这就是当前AI代理在处理长期任务时面临的核心挑战。&lt;/p&gt;
&lt;p&gt;尽管Claude Agent SDK具备上下文压缩（compaction）等高级功能，但仅靠这些还不足以让代理持续构建高质量的应用程序。在实际测试中，即使是Opus 4.5这样的前沿模型，在多次会话后仍会失败，主要表现为两种模式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;过度尝试&lt;/strong&gt;：代理试图一次性完成整个应用，导致上下文耗尽，留下半成品&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;提前完成&lt;/strong&gt;：代理看到某些功能已实现，就错误地宣布项目完成&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;graph TD
    A[初始提示] --&amp;gt; B{代理行为}
    B --&amp;gt;|过度尝试| C[一次性实现太多功能]
    B --&amp;gt;|提前完成| D[看到部分功能就宣布完成]
    C --&amp;gt; E[上下文耗尽]
    D --&amp;gt; F[功能不完整]
    E --&amp;gt; G[后续会话无法继续]
    F --&amp;gt; G
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;解决方案：双代理架构&lt;/h2&gt;
&lt;p&gt;Anthropic团队开发了一个双阶段解决方案，让Claude能够在多个上下文窗口中高效工作：&lt;/p&gt;
&lt;h3&gt;1. 初始化代理（Initializer Agent）&lt;/h3&gt;
&lt;p&gt;第一个会话使用专门的提示，让初始化代理设置环境：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;创建&lt;code&gt;init.sh&lt;/code&gt;脚本启动开发服务器&lt;/li&gt;
&lt;li&gt;生成&lt;code&gt;claude-progress.txt&lt;/code&gt;进度跟踪文件&lt;/li&gt;
&lt;li&gt;进行初始git提交，记录添加的文件&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 编码代理（Coding Agent）&lt;/h3&gt;
&lt;p&gt;后续每个会话都使用编码代理，专注于：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;增量式迭代开发（一次只处理一个功能）&lt;/li&gt;
&lt;li&gt;留下清晰的工件供下次会话使用&lt;/li&gt;
&lt;li&gt;保持环境在&quot;干净状态&quot;（适合合并到主分支的代码）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;核心组件详解&lt;/h2&gt;
&lt;h3&gt;特性列表：防止过度尝试和提前完成&lt;/h3&gt;
&lt;p&gt;初始化代理会生成一个包含200+功能的详细列表，每个功能都有明确的测试步骤：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
    &quot;category&quot;: &quot;functional&quot;,
    &quot;description&quot;: &quot;New chat button creates a fresh conversation&quot;,
    &quot;steps&quot;: [
      &quot;Navigate to main interface&quot;,
      &quot;Click the &apos;New Chat&apos; button&quot;,
      &quot;Verify a new conversation is created&quot;,
      &quot;Check that chat area shows welcome state&quot;,
      &quot;Verify conversation appears in sidebar&quot;
    ],
    &quot;passes&quot;: false
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个JSON格式的文件防止了代理随意修改或删除测试，确保功能完整性。&lt;/p&gt;
&lt;h3&gt;增量进展：一次只做一件事&lt;/h3&gt;
&lt;p&gt;编码代理被明确指示一次只处理一个功能。每次会话结束时，代理需要：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提交代码到git，附带描述性提交信息&lt;/li&gt;
&lt;li&gt;更新进度文件，记录已完成的工作&lt;/li&gt;
&lt;li&gt;确保代码状态干净，无重大bug&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;flowchart LR
    A[读取进度文件] --&amp;gt; B[查看git日志]
    B --&amp;gt; C[选择最高优先级未完成功能]
    C --&amp;gt; D[实现功能]
    D --&amp;gt; E[端到端测试]
    E --&amp;gt; F{测试通过?}
    F --&amp;gt;|是| G[更新功能状态为passing]
    F --&amp;gt;|否| H[修复bug]
    H --&amp;gt; E
    G --&amp;gt; I[git提交]
    I --&amp;gt; J[更新进度文件]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;端到端测试：确保真正完成&lt;/h3&gt;
&lt;p&gt;Anthropic发现，代理倾向于在没有充分测试的情况下标记功能为完成。解决方案是提供浏览器自动化工具（如Puppeteer），让代理像真实用户一样测试应用：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.anthropic.com/_next/image?url=https%3A%2F%2Fwww-cdn.anthropic.com%2Fimages%2F4zrzovbb%2Fwebsite%2Ff94c2257964fb2d623f1e81f874977ebfc0986bc-1920x1080.gif&amp;amp;w=3840&amp;amp;q=75&quot; alt=&quot;url=https%3A%2F%2Fwww-cdn.anthropic.com%2Fimages%2F4zrzovbb%2Fwebsite%2Ff94c2257964fb2d623f1e81f874977ebfc0986bc-1920x1080.gif&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;典型会话流程&lt;/h2&gt;
&lt;p&gt;一个典型的编码代理会话开始时会执行以下步骤：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Assistant] I&apos;ll start by getting my bearings and understanding the current state of the project.
[Tool Use] &amp;lt;bash - pwd&amp;gt;
[Tool Use] &amp;lt;read - claude-progress.txt&amp;gt;
[Tool Use] &amp;lt;read - feature_list.json&amp;gt;
[Assistant] Let me check the git log to see recent work.
[Tool Use] &amp;lt;bash - git log --oneline -20&amp;gt;
[Assistant] Now let me check if there&apos;s an init.sh script to restart the servers.
&amp;lt;Starts the development server&amp;gt;
[Assistant] Excellent! Now let me navigate to the application and verify that some fundamental features are still working.
&amp;lt;Tests basic functionality&amp;gt;
[Assistant] Based on my verification testing, I can see that the fundamental functionality is working well. The core chat features, theme switching, conversation loading, and error handling are all functioning correctly. Now let me review the tests.json file more comprehensively to understand what needs to be implemented next.
&amp;lt;Starts work on a new feature&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;常见失败模式及解决方案&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;问题&lt;/th&gt;
&lt;th&gt;初始化代理行为&lt;/th&gt;
&lt;th&gt;编码代理行为&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;过早宣布项目完成&lt;/td&gt;
&lt;td&gt;设置特性列表文件，包含基于输入规范的所有端到端功能描述&lt;/td&gt;
&lt;td&gt;会话开始时读取特性列表文件，选择单个功能处理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;留下有bug或未记录进度的环境&lt;/td&gt;
&lt;td&gt;创建初始git仓库和进度笔记文件&lt;/td&gt;
&lt;td&gt;会话开始时读取进度笔记和git日志，运行基础测试；会话结束时写入git提交和进度更新&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;过早标记功能为完成&lt;/td&gt;
&lt;td&gt;设置特性列表文件&lt;/td&gt;
&lt;td&gt;自我验证所有功能，仅在仔细测试后标记为&quot;passing&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;花时间弄清楚如何运行应用&lt;/td&gt;
&lt;td&gt;编写&lt;code&gt;init.sh&lt;/code&gt;脚本来运行开发服务器&lt;/td&gt;
&lt;td&gt;会话开始时读取&lt;code&gt;init.sh&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;未来方向&lt;/h2&gt;
&lt;p&gt;虽然这个框架在全栈Web应用开发中表现出色，但仍有改进空间：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;多代理架构&lt;/strong&gt;：专业化代理（测试代理、质量保证代理、代码清理代理）可能在软件开发生命周期的子任务中表现更好&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;领域泛化&lt;/strong&gt;：将这些原则应用到科学研究、金融建模等其他需要长期运行代理的领域&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;结论&lt;/h2&gt;
&lt;p&gt;构建能够跨多个会话持续工作的AI代理，关键在于&lt;strong&gt;环境管理&lt;/strong&gt;和&lt;strong&gt;增量进展&lt;/strong&gt;。Anthropic的解决方案证明，通过精心设计的初始化流程和严格的进度跟踪机制，AI代理可以在复杂项目中保持连贯性和效率。&lt;/p&gt;
&lt;p&gt;真正的产品突破不在于模型能力的提升，而在于&lt;strong&gt;工作流程的设计&lt;/strong&gt;。当我们在提示工程中融入软件工程的最佳实践时，AI代理就能像人类团队一样，在长期项目中取得成功。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>如何构建一个专业的 Solana 交易机器人：从架构设计到实战落地</title><link>https://blog.ithuo.net/posts/solana-trading-bot-system-design/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/solana-trading-bot-system-design/</guid><pubDate>Mon, 10 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;前言&lt;/h1&gt;
&lt;p&gt;在 Solana 生态中，交易机器人（Trading Bot）已经成为 DeFi 交易者的重要工具。一个优秀的交易机器人需要具备&lt;strong&gt;实时监听、快速决策、可靠执行、风险控制&lt;/strong&gt;等核心能力。本文将深入探讨如何从零开始设计和实现一个生产级的交易机器人系统。&lt;/p&gt;
&lt;h1&gt;一、整体架构设计&lt;/h1&gt;
&lt;h3&gt;1.1 核心组件架构&lt;/h3&gt;
&lt;p&gt;一个完整的交易机器人系统应该包含以下核心模块：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;graph TB
    subgraph &quot;数据层&quot;
        A1[链上数据流&amp;lt;br/&amp;gt;Geyser/WebSocket]
        A2[区块数据&amp;lt;br/&amp;gt;Block Data]
        A3[账户状态&amp;lt;br/&amp;gt;Account State]
    end
    
    subgraph &quot;监听层&quot;
        B1[交易监听器&amp;lt;br/&amp;gt;Transaction Monitor]
        B2[账户监听器&amp;lt;br/&amp;gt;Account Monitor]
        B3[区块监听器&amp;lt;br/&amp;gt;Block Monitor]
    end
    
    subgraph &quot;策略引擎&quot;
        C1[信号识别&amp;lt;br/&amp;gt;Signal Detection]
        C2[策略评估&amp;lt;br/&amp;gt;Strategy Evaluation]
        C3[决策生成&amp;lt;br/&amp;gt;Decision Engine]
    end
    
    subgraph &quot;风控层&quot;
        D1[风险检查&amp;lt;br/&amp;gt;Risk Checker]
        D2[限额管理&amp;lt;br/&amp;gt;Limit Manager]
        D3[黑名单过滤&amp;lt;br/&amp;gt;Blacklist Filter]
    end
    
    subgraph &quot;执行层&quot;
        E1[交易构建器&amp;lt;br/&amp;gt;Transaction Builder]
        E2[多路发送器&amp;lt;br/&amp;gt;Multi-Channel Sender]
        E3[状态跟踪器&amp;lt;br/&amp;gt;State Tracker]
    end
    
    subgraph &quot;基础设施&quot;
        F1[RPC 连接池&amp;lt;br/&amp;gt;RPC Pool]
        F2[配置管理&amp;lt;br/&amp;gt;Config Manager]
        F3[日志监控&amp;lt;br/&amp;gt;Logging &amp;amp; Metrics]
    end
    
    A1 --&amp;gt; B1
    A2 --&amp;gt; B2
    A3 --&amp;gt; B3
    B1 --&amp;gt; C1
    B2 --&amp;gt; C1
    B3 --&amp;gt; C1
    C1 --&amp;gt; C2
    C2 --&amp;gt; C3
    C3 --&amp;gt; D1
    D1 --&amp;gt; D2
    D2 --&amp;gt; D3
    D3 --&amp;gt; E1
    E1 --&amp;gt; E2
    E2 --&amp;gt; E3
    E3 --&amp;gt; F3
    
    F1 --&amp;gt; E2
    F2 --&amp;gt; C2
    F2 --&amp;gt; D1
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;1.2 数据流向&lt;/h3&gt;
&lt;p&gt;系统的数据流向遵循&quot;&lt;strong&gt;监听 → 解析 → 决策 → 执行 → 反馈&lt;/strong&gt;&quot;的闭环：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sequenceDiagram
    participant Chain as Solana 链
    participant Stream as 数据流服务
    participant Monitor as 监听模块
    participant Parser as 交易解析器
    participant Strategy as 策略引擎
    participant Risk as 风控模块
    participant Builder as 交易构建器
    participant RPC as RPC 发送层
    participant DB as 数据记录
    
    Chain-&amp;gt;&amp;gt;Stream: 新交易/区块/账户变更
    Stream-&amp;gt;&amp;gt;Monitor: 推送实时数据
    Monitor-&amp;gt;&amp;gt;Parser: 原始交易数据
    Parser-&amp;gt;&amp;gt;Parser: 解析 Swap 信息&amp;lt;br/&amp;gt;(TokenIn/Out, Amount, Pool)
    Parser-&amp;gt;&amp;gt;Strategy: 结构化交易信息
    Strategy-&amp;gt;&amp;gt;Strategy: 策略匹配与评估
    Strategy-&amp;gt;&amp;gt;Risk: 交易信号
    Risk-&amp;gt;&amp;gt;Risk: 风险检查&amp;lt;br/&amp;gt;(限额/黑名单/冷却期)
    Risk-&amp;gt;&amp;gt;Builder: 通过风控
    Builder-&amp;gt;&amp;gt;Builder: 构建交易指令&amp;lt;br/&amp;gt;(Instruction + Priority Fee)
    Builder-&amp;gt;&amp;gt;RPC: 签名后的交易
    RPC-&amp;gt;&amp;gt;Chain: 并行发送到多个节点
    Chain--&amp;gt;&amp;gt;RPC: 交易确认
    RPC--&amp;gt;&amp;gt;DB: 记录交易结果
    DB-&amp;gt;&amp;gt;Strategy: 更新持仓状态
    Strategy-&amp;gt;&amp;gt;Monitor: 继续监听持仓变化
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1&gt;二、核心功能模块详解&lt;/h1&gt;
&lt;h3&gt;2.1 数据监听层&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;目标&lt;/strong&gt;：实时获取链上数据，确保不错过任何交易机会。&lt;/p&gt;
&lt;h3&gt;2.1.1 数据源选择&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;方案一：Yellowstone Geyser（推荐）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;优势&lt;/strong&gt;：低延迟、高吞吐、支持复杂过滤&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：需要监听特定账户或程序的所有交易&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实现方式&lt;/strong&gt;：gRPC 流式订阅，支持账户过滤、交易过滤&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;方案二：WebSocket RPC&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;优势&lt;/strong&gt;：简单易用、无需额外服务&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：监听特定账户余额变化&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;限制&lt;/strong&gt;：延迟较高，不适合高频交易&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;方案三：自建节点&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;优势&lt;/strong&gt;：完全控制、无依赖&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：大规模部署、需要自定义逻辑&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;成本&lt;/strong&gt;：需要维护 Solana 验证节点，并且机器配置和机房都要选择高配，与官方机房低延迟，例如法兰克福等&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2.1.2 监听策略&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;graph LR
    A[监听目标] --&amp;gt; B{监听类型}
    B --&amp;gt;|账户监听| C[特定钱包地址&amp;lt;br/&amp;gt;监控其所有交易]
    B --&amp;gt;|程序监听| D[DEX 程序地址&amp;lt;br/&amp;gt;监控所有 Swap]
    B --&amp;gt;|Token 监听| E[Token Mint 地址&amp;lt;br/&amp;gt;监控该 Token 所有交易]
    B --&amp;gt;|区块监听| F[区块元数据&amp;lt;br/&amp;gt;获取最新 Blockhash]
    
    C --&amp;gt; G[Smart Money 跟踪]
    D --&amp;gt; H[新币发现]
    E --&amp;gt; I[持仓监控]
    F --&amp;gt; J[交易构建]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;关键注意事项&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;去重机制&lt;/strong&gt;：使用 Bloom Filter 或内存缓存避免重复处理&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;连接管理&lt;/strong&gt;：实现自动重连和心跳检测&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;消息缓冲&lt;/strong&gt;：使用有界队列防止内存溢出&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;错误处理&lt;/strong&gt;：区分临时错误和永久错误，采用不同重试策略&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2.2 交易解析层&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;目标&lt;/strong&gt;：从原始交易数据中提取关键信息。&lt;/p&gt;
&lt;h3&gt;2.2.1 解析流程&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;flowchart TD
    A[原始交易] --&amp;gt; B{交易类型识别}
    B --&amp;gt;|Swap 交易| C[解析 Swap 指令]
    B --&amp;gt;|创建交易| D[解析创建指令]
    B --&amp;gt;|其他| E[跳过]
    
    C --&amp;gt; F[提取关键信息]
    F --&amp;gt; G[TokenIn/TokenOut]
    F --&amp;gt; H[交易金额]
    F --&amp;gt; I[池子地址]
    F --&amp;gt; J[交易方向&amp;lt;br/&amp;gt;买入/卖出]
    F --&amp;gt; K[协议类型&amp;lt;br/&amp;gt;PumpFun/Jupiter/Raydium]
    
    G --&amp;gt; L[结构化数据]
    H --&amp;gt; L
    I --&amp;gt; L
    J --&amp;gt; L
    K --&amp;gt; L
    
    L --&amp;gt; M[传递给策略引擎]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;解析要点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;多协议支持&lt;/strong&gt;：不同 DEX 的指令格式不同，需要适配器模式&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inner Instructions&lt;/strong&gt;：Solana 交易可能包含嵌套指令，需要递归解析&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据验证&lt;/strong&gt;：验证解析结果的完整性和正确性&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能优化&lt;/strong&gt;：使用缓存避免重复解析相同类型的交易&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2.3 策略引擎&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;目标&lt;/strong&gt;：基于解析后的数据，判断是否执行交易。&lt;/p&gt;
&lt;h3&gt;2.3.1 策略类型&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;mindmap
  root((策略引擎))
    新币狙击
      监听创建事件
      快速买入
      短期持有
    跟单策略
      监控 Smart Money
      复制交易
      动态调整
    套利策略
      价差检测
      跨 DEX 套利
      三角套利
    趋势跟踪
      价格动量
      成交量分析
      技术指标
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2.3.2 策略评估流程&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;flowchart TD
    A[交易信号] --&amp;gt; B{策略匹配}
    B --&amp;gt;|匹配策略1| C1[策略1评估]
    B --&amp;gt;|匹配策略2| C2[策略2评估]
    B --&amp;gt;|无匹配| E[丢弃]
    
    C1 --&amp;gt; D{评估结果}
    C2 --&amp;gt; D
    D --&amp;gt;|通过| F[计算交易参数]
    D --&amp;gt;|拒绝| E
    
    F --&amp;gt; G[买入金额]
    F --&amp;gt; H[滑点容忍度]
    F --&amp;gt; I[持仓时间]
    F --&amp;gt; J[止损/止盈]
    
    G --&amp;gt; K[传递给风控层]
    H --&amp;gt; K
    I --&amp;gt; K
    J --&amp;gt; K
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;策略设计原则&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;模块化&lt;/strong&gt;：每个策略独立实现，便于测试和优化&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可配置&lt;/strong&gt;：策略参数通过配置文件动态调整&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可扩展&lt;/strong&gt;：预留接口，方便添加新策略&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能优先&lt;/strong&gt;：评估逻辑要轻量，避免阻塞主流程&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2.4 风控模块&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;目标&lt;/strong&gt;：在执行交易前进行风险检查，保护资金安全。&lt;/p&gt;
&lt;h3&gt;2.4.1 风控检查项&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;graph TD
    A[交易请求] --&amp;gt; B[余额检查]
    B --&amp;gt; C[限额检查]
    C --&amp;gt; D[频率限制]
    D --&amp;gt; E[黑名单检查]
    E --&amp;gt; F[滑点检查]
    F --&amp;gt; G[持仓检查]
    G --&amp;gt; H{全部通过?}
    H --&amp;gt;|是| I[允许执行]
    H --&amp;gt;|否| J[拒绝并记录]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;关键风控规则&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;余额检查&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;确保账户有足够 SOL 支付交易费和交易金额&lt;/li&gt;
&lt;li&gt;预留安全余量（建议 0.1 SOL）&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;限额管理&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;单笔限额&lt;/strong&gt;：限制单次交易的最大金额&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;日限额&lt;/strong&gt;：限制每日总交易金额&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;持仓限额&lt;/strong&gt;：限制同时持有的 Token 数量&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;频率控制&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;冷却期&lt;/strong&gt;：同一 Token 的两次买入间隔&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;窗口限制&lt;/strong&gt;：单位时间内的最大交易次数&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;去重机制&lt;/strong&gt;：避免重复买入同一 Token&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;黑名单过滤&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Token 黑名单：已知的 Rug Pull 或问题 Token&lt;/li&gt;
&lt;li&gt;地址黑名单：已知的恶意地址&lt;/li&gt;
&lt;li&gt;动态更新：支持热更新黑名单&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;滑点保护&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;设置最大滑点容忍度&lt;/li&gt;
&lt;li&gt;实时计算预期滑点&lt;/li&gt;
&lt;li&gt;超过阈值自动拒绝&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2.5 交易执行层&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;目标&lt;/strong&gt;：快速、可靠地将交易提交到链上。&lt;/p&gt;
&lt;h3&gt;2.5.1 执行流程&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;sequenceDiagram
    participant Strategy as 策略引擎
    participant Builder as 交易构建器
    participant Signer as 签名器
    participant Sender as 多路发送器
    participant RPC1 as RPC 节点1
    participant RPC2 as RPC 节点2
    participant RPC3 as RPC 节点3
    participant Chain as Solana 链
    
    Strategy-&amp;gt;&amp;gt;Builder: 交易参数&amp;lt;br/&amp;gt;(Token, Amount, Slippage)
    Builder-&amp;gt;&amp;gt;Builder: 选择协议适配器&amp;lt;br/&amp;gt;(PumpFun/Jupiter/...)
    Builder-&amp;gt;&amp;gt;Builder: 构建指令序列&amp;lt;br/&amp;gt;(Compute Budget + Swap + Tip)
    Builder-&amp;gt;&amp;gt;Builder: 获取最新 Blockhash
    Builder-&amp;gt;&amp;gt;Signer: 完整交易
    Signer-&amp;gt;&amp;gt;Signer: 使用私钥签名
    Signer-&amp;gt;&amp;gt;Sender: 签名后的交易
    
    par 并行发送
        Sender-&amp;gt;&amp;gt;RPC1: 发送交易
        Sender-&amp;gt;&amp;gt;RPC2: 发送交易
        Sender-&amp;gt;&amp;gt;RPC3: 发送交易
    end
    
    RPC1-&amp;gt;&amp;gt;Chain: 提交交易
    RPC2-&amp;gt;&amp;gt;Chain: 提交交易
    RPC3-&amp;gt;&amp;gt;Chain: 提交交易
    
    Chain--&amp;gt;&amp;gt;RPC1: 交易确认
    RPC1--&amp;gt;&amp;gt;Sender: 返回结果
    Sender-&amp;gt;&amp;gt;Strategy: 执行结果
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2.5.2 多路发送策略&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;为什么需要多路发送？&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;提高成功率&lt;/strong&gt;：单个 RPC 节点可能临时故障&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;降低延迟&lt;/strong&gt;：选择响应最快的节点&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;负载分散&lt;/strong&gt;：避免单点限流&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;容错能力&lt;/strong&gt;：一个节点失败不影响整体&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;实现要点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;并行发送&lt;/strong&gt;：同时发送到多个 RPC 节点&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;竞速模式&lt;/strong&gt;：第一个成功的响应即返回&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;超时控制&lt;/strong&gt;：设置合理的超时时间（建议 5-8 秒）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;错误处理&lt;/strong&gt;：区分网络错误和交易失败&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2.5.3 优先费策略&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;优先费（Priority Fee）的作用&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提高交易被打包的概率&lt;/li&gt;
&lt;li&gt;在拥堵时获得优先处理&lt;/li&gt;
&lt;li&gt;影响交易确认速度&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;动态调整策略&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;基础费用&lt;/strong&gt;：根据网络拥堵情况动态获取&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tip 费用&lt;/strong&gt;：根据交易紧急程度调整&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;费用上限&lt;/strong&gt;：设置最大费用，避免过度支付&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2.6 状态管理&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;目标&lt;/strong&gt;：跟踪每笔交易的状态，支持持仓管理和卖出决策。&lt;/p&gt;
&lt;h3&gt;2.6.1 状态流转&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;stateDiagram-v2
    [*] --&amp;gt; 监听中: 启动监听
    监听中 --&amp;gt; 信号识别: 发现交易机会
    信号识别 --&amp;gt; 策略评估: 匹配策略
    策略评估 --&amp;gt; 风控检查: 通过评估
    风控检查 --&amp;gt; 构建交易: 通过风控
    构建交易 --&amp;gt; 发送中: 交易已签名
    发送中 --&amp;gt; 持仓中: 交易确认
    发送中 --&amp;gt; 失败: 交易失败
    持仓中 --&amp;gt; 卖出中: 触发卖出
    持仓中 --&amp;gt; 止损: 价格下跌
    卖出中 --&amp;gt; 已完成: 卖出成功
    卖出中 --&amp;gt; 失败: 卖出失败
    失败 --&amp;gt; 监听中: 清理状态
    已完成 --&amp;gt; 监听中: 记录收益
    止损 --&amp;gt; 监听中: 记录损失
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2.6.2 持仓管理&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;关键数据&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;买入价格&lt;/strong&gt;：用于计算盈亏&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;买入数量&lt;/strong&gt;：当前持仓量&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;持仓时间&lt;/strong&gt;：用于动态调整卖出策略&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;目标价格&lt;/strong&gt;：止盈/止损价格&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;卖出触发条件&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定时卖出&lt;/strong&gt;：达到预设持仓时间&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;价格触发&lt;/strong&gt;：达到止盈或止损价格&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跟踪卖出&lt;/strong&gt;：跟踪的钱包卖出时跟随&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;信号卖出&lt;/strong&gt;：策略生成卖出信号&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h1&gt;三、完整交易流程&lt;/h1&gt;
&lt;h3&gt;3.1 从监听到执行的完整链路&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;flowchart TD
    Start([系统启动]) --&amp;gt; Init[初始化组件]
    Init --&amp;gt; Connect[连接数据源]
    Connect --&amp;gt; Subscribe[订阅链上事件]
    
    Subscribe --&amp;gt; Wait{等待事件}
    Wait --&amp;gt;|新交易| Parse[解析交易]
    Wait --&amp;gt;|区块更新| UpdateBlock[更新 Blockhash]
    Wait --&amp;gt;|账户变更| UpdateAccount[更新账户状态]
    
    Parse --&amp;gt; Filter{过滤条件}
    Filter --&amp;gt;|不匹配| Wait
    Filter --&amp;gt;|匹配| Extract[提取关键信息]
    
    Extract --&amp;gt; Strategy{策略评估}
    Strategy --&amp;gt;|不通过| Wait
    Strategy --&amp;gt;|通过| Calculate[计算交易参数]
    
    Calculate --&amp;gt; Risk{风控检查}
    Risk --&amp;gt;|不通过| Log[记录拒绝原因]
    Risk --&amp;gt;|通过| Build[构建交易]
    
    Log --&amp;gt; Wait
    Build --&amp;gt; Sign[签名交易]
    Sign --&amp;gt; Send[多路发送]
    
    Send --&amp;gt; Confirm{等待确认}
    Confirm --&amp;gt;|成功| Update[更新持仓状态]
    Confirm --&amp;gt;|失败| Retry{重试?}
    
    Retry --&amp;gt;|是| Build
    Retry --&amp;gt;|否| Log
    Update --&amp;gt; Monitor[监听持仓变化]
    Monitor --&amp;gt; Sell{卖出条件?}
    
    Sell --&amp;gt;|未满足| Monitor
    Sell --&amp;gt;|满足| BuildSell[构建卖出交易]
    BuildSell --&amp;gt; Sign
    Sign --&amp;gt; Send
    
    Update --&amp;gt; Record[记录收益]
    Record --&amp;gt; Wait
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3.2 关键时间节点&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;时间敏感操作&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;信号识别&lt;/strong&gt;：&amp;lt; 10ms（内存处理）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;策略评估&lt;/strong&gt;：&amp;lt; 50ms（避免复杂计算）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;交易构建&lt;/strong&gt;：&amp;lt; 100ms（包含 RPC 调用获取 Blockhash）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;交易发送&lt;/strong&gt;：&amp;lt; 200ms（并行发送）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;总延迟&lt;/strong&gt;：&amp;lt; 500ms（从信号到上链）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;优化建议&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;预构建常用交易模板&lt;/li&gt;
&lt;li&gt;缓存 Blockhash（有效期约 60 秒）&lt;/li&gt;
&lt;li&gt;使用 Nonce Account 避免 Blockhash 过期&lt;/li&gt;
&lt;li&gt;预签名部分指令（如 Compute Budget）&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h1&gt;四、收益记录与分析&lt;/h1&gt;
&lt;h3&gt;4.1 收益计算&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;收益 = 卖出金额 - 买入金额 - 交易费用&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关键指标&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;总收益&lt;/strong&gt;：累计盈亏&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;胜率&lt;/strong&gt;：盈利交易占比&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;平均收益&lt;/strong&gt;：单笔平均盈亏&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;最大回撤&lt;/strong&gt;：最大连续亏损&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;夏普比率&lt;/strong&gt;：风险调整后收益&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4.2 数据记录&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;记录内容&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;交易记录&lt;/strong&gt;：每笔买卖的详细信息&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;持仓记录&lt;/strong&gt;：当前持仓状态&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;收益统计&lt;/strong&gt;：按日/周/月统计&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;策略表现&lt;/strong&gt;：各策略的独立统计&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h1&gt;五、最佳实践与注意事项&lt;/h1&gt;
&lt;h3&gt;5.1 架构设计原则&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;模块化设计&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;每个模块职责单一&lt;/li&gt;
&lt;li&gt;模块间通过接口通信&lt;/li&gt;
&lt;li&gt;便于测试和维护&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;异步处理&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;使用消息队列解耦&lt;/li&gt;
&lt;li&gt;避免阻塞主流程&lt;/li&gt;
&lt;li&gt;提高系统吞吐量&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;容错设计&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;关键操作有重试机制&lt;/li&gt;
&lt;li&gt;失败不影响其他交易&lt;/li&gt;
&lt;li&gt;完善的错误日志&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;可观测性&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;关键指标监控&lt;/li&gt;
&lt;li&gt;详细的日志记录&lt;/li&gt;
&lt;li&gt;性能指标追踪&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;5.2 安全注意事项&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;私钥管理&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;私钥加密存储&lt;/li&gt;
&lt;li&gt;使用硬件钱包（如 Ledger/OneKey）&lt;/li&gt;
&lt;li&gt;避免硬编码私钥&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;权限控制&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;最小权限原则（善用IAM结合KMS管理）&lt;/li&gt;
&lt;li&gt;交易限额设置&lt;/li&gt;
&lt;li&gt;操作审计日志&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;风险控制&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;设置止损机制&lt;/li&gt;
&lt;li&gt;定期检查余额&lt;/li&gt;
&lt;li&gt;异常交易告警&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;5.3 性能优化&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;连接池管理&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;RPC 连接复用&lt;/li&gt;
&lt;li&gt;合理的连接数&lt;/li&gt;
&lt;li&gt;连接健康检查&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;缓存策略&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;缓存 Blockhash&lt;/li&gt;
&lt;li&gt;缓存账户信息&lt;/li&gt;
&lt;li&gt;缓存策略配置&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;资源限制&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;限制并发交易数&lt;/li&gt;
&lt;li&gt;限制内存使用&lt;/li&gt;
&lt;li&gt;限制 CPU 使用&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;5.4 监控与告警&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;关键指标&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;交易成功率&lt;/strong&gt;：交易确认率&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;平均延迟&lt;/strong&gt;：从信号到确认的时间&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;错误率&lt;/strong&gt;：各类错误的发生频率&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;资金使用率&lt;/strong&gt;：当前资金占用比例&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;告警规则&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;连续失败超过阈值&lt;/li&gt;
&lt;li&gt;余额低于安全线&lt;/li&gt;
&lt;li&gt;异常大额交易&lt;/li&gt;
&lt;li&gt;系统资源告警&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h1&gt;六、技术选型建议&lt;/h1&gt;
&lt;h3&gt;6.1 数据源&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方案&lt;/th&gt;
&lt;th&gt;优势&lt;/th&gt;
&lt;th&gt;劣势&lt;/th&gt;
&lt;th&gt;适用场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Yellowstone Geyser&lt;/td&gt;
&lt;td&gt;低延迟、高吞吐&lt;/td&gt;
&lt;td&gt;需要付费或自建&lt;/td&gt;
&lt;td&gt;生产环境&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WebSocket RPC&lt;/td&gt;
&lt;td&gt;简单易用&lt;/td&gt;
&lt;td&gt;延迟较高&lt;/td&gt;
&lt;td&gt;开发测试&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;自建节点&lt;/td&gt;
&lt;td&gt;完全控制&lt;/td&gt;
&lt;td&gt;成本高、维护复杂&lt;/td&gt;
&lt;td&gt;大规模部署&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;6.2 RPC 服务&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;服务&lt;/th&gt;
&lt;th&gt;特点&lt;/th&gt;
&lt;th&gt;推荐场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Jito&lt;/td&gt;
&lt;td&gt;Bundle 打包、保证顺序&lt;/td&gt;
&lt;td&gt;套利、MEV&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BlockRazor&lt;/td&gt;
&lt;td&gt;专业中继、低延迟&lt;/td&gt;
&lt;td&gt;高频交易&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Helius&lt;/td&gt;
&lt;td&gt;稳定可靠、功能丰富&lt;/td&gt;
&lt;td&gt;通用场景&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;QuickNode&lt;/td&gt;
&lt;td&gt;全球节点、高可用&lt;/td&gt;
&lt;td&gt;国际化需求&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h1&gt;参考资料&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.solana.com/&quot;&gt;Solana 官方文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.triton.one/&quot;&gt;Yellowstone Geyser 文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.jup.ag/&quot;&gt;Jupiter API 文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jito.wtf/docs/&quot;&gt;Jito 文档&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;本文档基于实际项目经验总结，仅供参考。投资有风险，入市需谨慎。&lt;/em&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>关于金融系统货币存储与计算的小Tips</title><link>https://blog.ithuo.net/posts/golang-financial-currency-storage-guide/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/golang-financial-currency-storage-guide/</guid><pubDate>Mon, 13 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;&lt;strong&gt;前言：一个“0.1 + 0.2”引发的血案&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;在任何一个程序员的职业生涯中，几乎都踩过浮点数精度的坑。当你写下 &lt;code&gt;fmt.Println(0.1 + 0.2)&lt;/code&gt;，期待得到 &lt;code&gt;0.3&lt;/code&gt; 时，屏幕上却赫然显示着 &lt;code&gt;0.30000000000000004&lt;/code&gt;。在日常业务中，这点误差或许可以忽略一笑，但在金融系统里，这微小的偏差就是“地雷”。&lt;/p&gt;
&lt;p&gt;想象一下，一个日交易量百万笔的支付系统，每笔交易都因为精度问题丢失或多出万分之一的金额，一天下来就是一笔巨大的资损，足以让任何一家公司陷入审计和合规的噩梦。&lt;/p&gt;
&lt;p&gt;因此在金融系统开发中，我们必须确立一条铁律：&lt;strong&gt;永远不要使用浮点数（如&lt;/strong&gt; &lt;strong&gt;&lt;code&gt;float64&lt;/code&gt;****）来存储和计算货币金额。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;那我们该如何做选择呢？当我们用 Go 作为后端语言，配合 PostgreSQL 或 MySQL 作为数据库时，该如何规范、安全、高效地处理 USD、CNY、BTC、ETH 这些形态各异的货币呢？本文将彻底厘清这个问题，给你一份拿来即用的实战指南。&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;&lt;strong&gt;内容：两条正道与 Go 的实现&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;抛开浮点数这个“伪选项”，我们面前有两条康庄大道：数据库层面的定点数类型，以及以最小单位为基准的整数存储。&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;方案一：&lt;strong&gt;&lt;strong&gt;&lt;code&gt;DECIMAL&lt;/code&gt;&lt;/strong&gt;&lt;/strong&gt;/****&lt;code&gt;NUMERIC&lt;/code&gt;&lt;/strong&gt; &lt;strong&gt;- 直观与精确的平衡&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;这是最符合人类直觉的方案。它将金额以我们熟悉的小数形式精确地存储在数据库中，从根本上杜绝了二进制浮点数的精度问题。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;在数据库中如何设计？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;无论是 PostgreSQL 还是 MySQL，都提供了标准的定点数类型。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PostgreSQL&lt;/strong&gt;: 使用 &lt;code&gt;NUMERIC(precision, scale)&lt;/code&gt; 或 &lt;code&gt;DECIMAL(precision, scale)&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MySQL&lt;/strong&gt;: 使用 &lt;code&gt;DECIMAL(precision, scale)&lt;/code&gt; (&lt;code&gt;NUMERIC&lt;/code&gt; 是其同义词)。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;precision&lt;/code&gt; 是总位数，&lt;code&gt;scale&lt;/code&gt; 是小数位数。为了兼容从只有 2 位小数的法币到有 18 位小数的 ETH，我们可以设计一个足够大的字段，如 &lt;code&gt;DECIMAL(36, 18)&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;表结构对比：&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;PostgreSQL&lt;/th&gt;
&lt;th&gt;MySQL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;主键&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BIGSERIAL PRIMARY KEY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BIGINT AUTO_INCREMENT PRIMARY KEY&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;金额字段&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;balance NUMERIC(36, 18)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;balance DECIMAL(36, 18)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;更新时间&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;updated_at TIMESTAMPTZ&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;updated_at TIMESTAMP&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;唯一索引&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UNIQUE(user_id, currency_code)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UNIQUE KEY uniq_user_currency (user_id, currency_code)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;PostgreSQL 建表示例：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE user_wallets (
    id BIGSERIAL PRIMARY KEY,
    user_id BIGINT NOT NULL,
    currency_code VARCHAR(10) NOT NULL,
    balance NUMERIC(36, 18) NOT NULL,
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    UNIQUE(user_id, currency_code)
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;MySQL 建表示例：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE user_wallets (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    user_id BIGINT NOT NULL,
    currency_code VARCHAR(10) NOT NULL,
    balance DECIMAL(36, 18) NOT NULL,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    UNIQUE KEY uniq_user_currency (user_id, currency_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Go 语言如何适配？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Go 的原生类型中没有与 &lt;code&gt;DECIMAL&lt;/code&gt; 直接对应的，但社区为我们提供了完美的解决方案：&lt;code&gt;shopspring/decimal&lt;/code&gt; 库。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go get github.com/shopspring/decimal
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个库可以与 &lt;code&gt;database/sql&lt;/code&gt; 无缝集成，让你在 Go 代码中直接操作高精度的十进制数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心转账逻辑示例：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
    &quot;database/sql&quot;
    &quot;fmt&quot;
    &quot;log&quot;

    &quot;github.com/shopspring/decimal&quot;
    // 根据数据库选择驱动
    _ &quot;github.com/lib/pq&quot;          // PostgreSQL
    // _ &quot;github.com/go-sql-driver/mysql&quot; // MySQL
)

// ... 数据库连接代码 ...

func addBalance(db *sql.DB, userID int64, currency string, amountStr string) error {
    addAmount, err := decimal.NewFromString(amountStr)
    if err != nil {
        return fmt.Errorf(&quot;invalid amount: %w&quot;, err)
    }

    tx, err := db.Begin()
    if err != nil {
        return err
    }
    defer tx.Rollback() // 安全起见

    var currentBalance decimal.Decimal
    // 注意占位符的差异: PostgreSQL ($1, $2) vs MySQL (?, ?)
    query := &quot;SELECT balance FROM user_wallets WHERE user_id = $1 AND currency_code = $2 FOR UPDATE&quot;
    // query := &quot;SELECT balance FROM user_wallets WHERE user_id = ? AND currency_code = ? FOR UPDATE&quot; // MySQL
    err = tx.QueryRow(query, userID, currency).Scan(&amp;amp;currentBalance)
    if err != nil {
        return err
    }

    newBalance := currentBalance.Add(addAmount)

    updateQuery := &quot;UPDATE user_wallets SET balance = $1 WHERE user_id = $2 AND currency_code = $3&quot;
    // updateQuery := &quot;UPDATE user_wallets SET balance = ? WHERE user_id = ? AND currency_code = ?&quot; // MySQL
    _, err = tx.Exec(updateQuery, newBalance, userID, currency)
    if err != nil {
        return err
    }

    return tx.Commit()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;strong&gt;方案二：****&lt;code&gt;BIGINT&lt;/code&gt;&lt;/strong&gt; &lt;strong&gt;- 极致性能的最小单位法&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;这是高频交易和加密货币领域非常流行的方案。核心思想是：&lt;strong&gt;放弃小数，所有金额都以货币的最小单位作为整数存储。&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;100.50&lt;/code&gt; USD -&amp;gt; &lt;code&gt;10050&lt;/code&gt; (单位：分)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1.23456789&lt;/code&gt; BTC -&amp;gt; &lt;code&gt;123456789&lt;/code&gt; (单位：聪)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;10.123456789012345678&lt;/code&gt; ETH -&amp;gt; &lt;code&gt;10123456789012345678&lt;/code&gt; (单位：Wei)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;数据库设计：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;将金额字段就设计为简单的 &lt;code&gt;BIGINT&lt;/code&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE user_wallets_minimal_unit (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    user_id BIGINT NOT NULL,
    currency_code VARCHAR(10) NOT NULL,
    balance BIGINT NOT NULL, -- 核心变化：整数
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    UNIQUE KEY uniq_user_currency (user_id, currency_code)
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Go 语言如何配合？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在 Go 中，我们直接使用 &lt;code&gt;int64&lt;/code&gt;。但为了代码的可维护性和可读性，强烈建议封装一个 &lt;code&gt;Money&lt;/code&gt; 结构体。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
    &quot;fmt&quot;
    &quot;math/big&quot;
)

// 定义每种货币的精度（小数位数）
var currencyExponents = map[string]int{
    &quot;USD&quot;: 2,
    &quot;CNY&quot;: 2,
    &quot;BTC&quot;: 8,
    &quot;ETH&quot;: 18,
}

// Money 封装了金额和货币类型
type Money struct {
    Amount   int64   // 最小单位的金额
    Currency string // 货币代码
}

// NewMoney 从字符串创建 Money，确保转换过程无损
func NewMoney(amountStr string, currency string) (*Money, error) {
    exp, ok := currencyExponents[currency]
    if !ok {
        return nil, fmt.Errorf(&quot;unsupported currency: %s&quot;, currency)
    }

    // 使用 big.Rat 避免转换过程中的精度问题
    rat := new(big.Rat)
    _, ok = rat.SetString(amountStr)
    if !ok {
        return nil, fmt.Errorf(&quot;invalid amount string: %s&quot;, amountStr)
    }

    multiplier := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(exp)), nil)
    rat.Mul(rat, new(big.Rat).SetInt(multiplier))

    if !rat.IsInt() {
        return nil, fmt.Errorf(&quot;amount %s has too many decimal places for %s&quot;, amountStr, currency)
    }

    return &amp;amp;Money{
        Amount:   rat.Num().Int64(),
        Currency: currency,
    }, nil
}

// ToString 格式化为易读字符串
func (m *Money) ToString() string {
    exp := currencyExponents[m.Currency]
    divisor := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(exp)), nil)
    rat := new(big.Rat).SetFrac(big.NewInt(m.Amount), divisor)
    return rat.FloatString(exp)
}

func main() {
    btc, _ := NewMoney(&quot;0.00000001&quot;, &quot;BTC&quot;)
    fmt.Printf(&quot;Created: %s\\n&quot;, btc.ToString()) // 输出: Created: 0.00000001

    add, _ := NewMoney(&quot;0.5&quot;, &quot;BTC&quot;)
    newBtc, _ := btc.Add(add)
    fmt.Printf(&quot;New balance: %s\\n&quot;, newBtc.ToString()) // 输出: New balance: 0.50000001
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;strong&gt;查询、计算与统计&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;查询&lt;/strong&gt;：两种方案都非常直接。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;计算&lt;/strong&gt;：&lt;strong&gt;黄金法则：绝不在 SQL 中进行跨货币计算！&lt;/strong&gt; 正确做法是在应用层选定一个基准货币（如 USD），获取汇率，将所有涉及的金额统一转换为基准货币后，再进行加减运算。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;统计&lt;/strong&gt;：&lt;code&gt;SUM()&lt;/code&gt;, &lt;code&gt;AVG()&lt;/code&gt; 等聚合函数对两种方案都完美支持。
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DECIMAL&lt;/code&gt; 方案直接得到可读结果。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BIGINT&lt;/code&gt; 方案得到的是最小单位的总和，需要应用层用 &lt;code&gt;Money&lt;/code&gt; 结构体格式化后展示。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;结论&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;回到最初的问题，在金融系统中处理货币，我们有两个强大的武器库：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;DECIMAL&lt;/code&gt;&lt;/strong&gt; &lt;strong&gt;+&lt;/strong&gt; &lt;strong&gt;&lt;code&gt;shopspring/decimal&lt;/code&gt;&lt;/strong&gt;：这是&lt;strong&gt;普适性最强、开发效率最高&lt;/strong&gt;的方案。它在精度、直观性和可维护性上取得了绝佳平衡，是绝大多数金融应用的首选。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;BIGINT&lt;/code&gt;&lt;/strong&gt; &lt;strong&gt;+&lt;/strong&gt; &lt;strong&gt;&lt;code&gt;int64&lt;/code&gt;&lt;/strong&gt; &lt;strong&gt;+ 自定义结构体&lt;/strong&gt;：这是追求&lt;strong&gt;极致性能&lt;/strong&gt;的方案，尤其适合加密货币交易所这类对计算速度要求极高的场景。它以牺牲部分直观性为代价，换取了最快的整数运算性能。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;无论在产品种选择哪种方式，请牢记以下最佳实践：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;铁律&lt;/strong&gt;：永不使用浮点数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;事务&lt;/strong&gt;：所有金额变更操作必须在数据库事务中完成，并使用 &lt;code&gt;SELECT ... FOR UPDATE&lt;/code&gt; 防止并发冲突。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;审计&lt;/strong&gt;：建立详细的交易流水表，记录每一笔资金的来龙去脉，这是对账和追溯的基石。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API&lt;/strong&gt;：前后端交互时，金额字段统一使用字符串类型，避免 JavaScript 等客户端的精度问题。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MySQL&lt;/strong&gt;：如果你用 MySQL，&lt;strong&gt;请立刻检查并开启严格模式&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;构建金融系统，责任重大。对金钱的敬畏，应始于对数据类型的正确选择。希望这篇指南，能帮助你在 Go 的世界里，稳稳地托举起每一分钱的价值。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>如何用云原生“积木”搭出99.99%高可用DApp架构(AWS)</title><link>https://blog.ithuo.net/posts/startup-guide-sla-4-nines-aws-dapp-architecture/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/startup-guide-sla-4-nines-aws-dapp-architecture/</guid><pubDate>Mon, 13 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;引言&lt;/h3&gt;
&lt;p&gt;刚加入一个在做DApp的小团队，在Web3的世界里，用户的耐心和信任比金子还贵。如果在一次火爆的Mint活动中，或者在交易的关键时刻，服务挂了，那损失的不仅是钱，更是社区的信心。&lt;/p&gt;
&lt;p&gt;小公司里没有24/7轮班的SRE专家，也不可能自己去搭物理机房。所以我的信条很简单：&lt;strong&gt;把专业的事交给专业的人，我们专注于业务逻辑。而云厂商就是我们背后最专业的“基建狂魔”&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;在本篇文章中，我会介绍如何用AWS上那些看似复杂的服务，像搭乐高一样，快速构建一个能承诺SLA达到“4个九”（99.99%可用性）的后端架构。&lt;/p&gt;
&lt;h3&gt;架构速览&lt;/h3&gt;
&lt;p&gt;在深入细节之前，先看下整体的流量走向：&lt;/p&gt;
&lt;p&gt;用户 -&amp;gt; Vercel/Cloudflare (前端) -&amp;gt; AWS WAF (防火墙) -&amp;gt; Application Load Balancer (流量分发) -&amp;gt; ECS/EKS (核心服务) -&amp;gt; RDS/Redis (数据存储)&lt;/p&gt;
&lt;p&gt;这个流程里的每一个环节，都是为了“高可用”这三个字服务的。没有一个环节是单打独头的，它们都有备份，都有plan B。&lt;/p&gt;
&lt;h3&gt;第一站：前端 - 全球加速，永不宕机&lt;/h3&gt;
&lt;p&gt;DApp前端部署在Vercel或Cloudflare Pages上。为什么？因为它们天生就是全球化的、高可用的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;全球CDN：&lt;/strong&gt; 你的前端静态资源被缓存到全世界的边缘节点，用户无论在纽约还是东京，访问速度都飞快。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自带冗余：&lt;/strong&gt; 你不需要关心服务器挂掉的问题，这些平台会帮你搞定。一台服务器挂了？流量会自动切到另一台。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DDoS防护：&lt;/strong&gt; Cloudflare是这方面的专家，能帮你挡掉大部分网络攻击。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;最佳实践：&lt;/strong&gt; 把前端和后端域名分开。前端交给Vercel/Cloudflare，后端API用独立的子域名，这样权责分明，也更安全。&lt;/p&gt;
&lt;h3&gt;第二站：后端 - 稳定的基石&lt;/h3&gt;
&lt;p&gt;后端是整个系统的心脏，这里是重头戏。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 流量入口：保安(WAF) + 交通警察(ALB)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AWS WAF (Web Application Firewall):&lt;/strong&gt; 这是你服务的第一道门卫。不要让恶意流量直接打到你的服务器上。WAF能帮你过滤掉常见的SQL注入、跨站脚本（XSS）等攻击。对于DApp来说，防机器人、防刷子尤其重要，WAF可以设置规则，限制来自单一IP的请求频率。简单配置一下，就能获得巨大的安全收益。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Application Load Balancer (ALB):&lt;/strong&gt; 这是保证高可用的核心组件。千万不要把你的服务直接暴露在公网上，也&lt;strong&gt;千万不要只起一个服务实例&lt;/strong&gt;。ALB的作用就像一个极其聪明的交通警察：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;流量分发：&lt;/strong&gt; 它会把进来的请求，平均分配给你后端的多个服务实例（比如3个跑着你Go后端服务的ECS Task）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;健康检查：&lt;/strong&gt; ALB会像心跳一样，不停地“ping”你的每一个服务实例，问一句“你还活着吗？”。如果某个实例没反应，ALB会立刻把它从服务列表中踢出去，不再给它发流量，保证用户请求不会打到僵死的服务上。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自动扩容的入口：&lt;/strong&gt; 后面我们会讲到，ALB可以和自动扩容组（Auto Scaling Group）联动，流量大了就自动加机器。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2. 计算核心：ECS还是EKS？小团队的选择题&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们的Go服务、Temporal Worker都需要地方跑。AWS提供了两种主流的容器化方案：ECS和EKS。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ECS (Elastic Container Service):&lt;/strong&gt; AWS的“亲儿子”。如果你对Kubernetes（K8s）不熟悉，或者团队里没有专门的DevOps，&lt;strong&gt;强烈推荐从ECS + Fargate开始&lt;/strong&gt;。它足够简单，你只需要定义你的容器（用什么镜像，需要多少CPU/内存），然后告诉ECS：“给我跑3个实例”，剩下的事情AWS全帮你搞定。你不用管理底层的EC2服务器，省心省力。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EKS (Elastic Kubernetes Service):&lt;/strong&gt; K8s的托管服务。功能强大，是行业标准，生态丰富。但它的学习曲线也更陡峭。如果你有K8s经验，或者预见到未来业务会变得极其复杂，需要精细化的服务治理，那可以选择EKS。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3. 数据存储：把专业的事交给专家&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这是小团队最容易犯错的地方：为了省钱在EC2上自己装MySQL、PostgreSQL或者Redis。&lt;strong&gt;这是一个巨大的坑！&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;RDS (Relational Database Service):&lt;/strong&gt; 你的PGSQL和MySQL应该跑在RDS上。为什么？
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;一键开启Multi-AZ（多可用区）：&lt;/strong&gt; 这是实现数据库99.99%可用的“银弹”。你勾选这个选项后，AWS会自动在另一个物理隔离的机房里，为你创建一个一模一样、实时同步的备用数据库。当主数据库因为硬件故障、机房断电等问题挂掉时，AWS会在几十秒内自动切换到备用数据库。你的服务可能只会感受到一个短暂的连接中断，然后就自动恢复了。这个过程是全自动的，不需要你半夜三点爬起来手动操作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自动备份、快照、安全补丁：&lt;/strong&gt; 这些烦人的运维工作，RDS全包了。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ElastiCache for Redis:&lt;/strong&gt; 同样，不要自己搭Redis集群。用ElastiCache，它帮你处理了主从复制、故障切换等所有复杂问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;最佳实践：&lt;/strong&gt; 永远优先选择托管服务（RDS, ElastiCache）。你付的钱，买来的是稳定性和宝贵的睡眠时间。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. 异步任务：让Temporal稳固运行&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Temporal是处理复杂工作流的神器，但它本身也需要稳定运行。我们的做法是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;将Temporal Server也容器化&lt;/strong&gt;，像其他Go服务一样，部署在ECS或EKS上，同样运行多个实例，并挂在ALB后面。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;为Temporal配置一个高可用的RDS (PostgreSQL)作为其持久化层&lt;/strong&gt;。Temporal的可靠性，很大程度上依赖于其数据库的可靠性。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;第三站：监控与告警 - 架构的眼睛和耳朵&lt;/h3&gt;
&lt;p&gt;没有监控的系统，就像在闭着眼睛开车。承诺SLA，就必须知道系统在发生什么。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;OpenTelemetry Collector:&lt;/strong&gt; 这是一个“数据收集器”。你的Go应用、Temporal服务，都可以通过标准的OpenTelemetry SDK，把日志（Logs）、指标（Metrics）、链路（Traces）数据发射出来。Collector负责接收这些数据，然后统一发送到后端存储，比如CloudWatch。这样做的好处是标准化，以后你想换监控后端（比如换成DataDog），只需要改Collector的配置，业务代码一行都不用动。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CloudWatch:&lt;/strong&gt; AWS自带的监控“全家桶”。
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Logs:&lt;/strong&gt; 所有服务的日志都应该集中输出到CloudWatch Logs。出问题了，不用一台台登录服务器去翻日志文件。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Metrics:&lt;/strong&gt; 监控一切！ALB的请求延迟、5xx错误率；ECS服务的CPU、内存使用率；RDS的数据库连接数、CPU使用率。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Alarms (告警):&lt;/strong&gt; 这是最重要的！当问题发生时，它必须第一时间通知你。设置一些关键告警：
&lt;ul&gt;
&lt;li&gt;如果ALB的5xx错误率在5分钟内高于1%，立即通过短信/Slack通知我。&lt;/li&gt;
&lt;li&gt;如果RDS的CPU使用率连续10分钟超过80%，通知我。&lt;/li&gt;
&lt;li&gt;如果ECS服务的平均CPU使用率超过70%，自动触发扩容，增加一个新的服务实例。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;最佳实践：&lt;/strong&gt; 告警的原则是“宁滥勿缺”，但要避免“狼来了”。把真正紧急的告警（服务不可用）设置为最高优先级，通过电话或短信通知。次要的（资源紧张）则发到Slack或邮件。&lt;/p&gt;
&lt;h3&gt;总结：小团队的生存法则&lt;/h3&gt;
&lt;p&gt;想用小团队的资源撑起99.99%的SLA，秘诀不是技术有多高深，而是思路要转变：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;拥抱托管服务：&lt;/strong&gt; RDS、ALB、ECS Fargate、EKS 是你最好的朋友。别在造轮子上浪费时间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;冗余是一切：&lt;/strong&gt; 任何一个组件，都必须有备份。服务至少部署2个实例，数据库必须是Multi-AZ。杜绝任何单点故障。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自动化是关键：&lt;/strong&gt; 依赖自动健康检查、自动故障切换、自动扩容。让机器帮你做重复且重要的工作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;监控先行：&lt;/strong&gt; 在你写下第一行代码时，就该思考如何监控它。没有监控，一切高可用都是空谈。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;作为创业团队，我们最宝贵的资源是时间和专注力。把基础设施的重担交给云厂商，让我们能更专注于打磨DApp的核心功能和用户体验，这才是小团队在激烈竞争中活下来并脱颖而出的王道。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Solana 链上事件与交易监听</title><link>https://blog.ithuo.net/posts/solana-onchain-events-and-subscriptions/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/solana-onchain-events-and-subscriptions/</guid><pubDate>Tue, 17 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;一、为什么监听事件？&lt;/h2&gt;
&lt;p&gt;在真实业务中，我们经常需要「&lt;strong&gt;实时响应链上状态变化&lt;/strong&gt;」：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;钱包余额更新（收款到账）&lt;/li&gt;
&lt;li&gt;代币转账或 NFT 交易&lt;/li&gt;
&lt;li&gt;合约（Program）执行事件&lt;/li&gt;
&lt;li&gt;大额交易监控、套利机会识别&lt;/li&gt;
&lt;li&gt;扫链与索引器系统（Indexer）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以太坊使用 &lt;code&gt;eth_subscribe&lt;/code&gt; 来监听事件，&lt;/p&gt;
&lt;p&gt;而 &lt;strong&gt;Solana&lt;/strong&gt; 则提供了两种主流方式：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方式&lt;/th&gt;
&lt;th&gt;协议&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;WebSocket 监听&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;WSS&lt;/td&gt;
&lt;td&gt;最常用，直接从 RPC 节点订阅实时消息&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;gRPC 监听&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;gRPC Stream&lt;/td&gt;
&lt;td&gt;更高性能、结构化更强，适合自建节点或生产系统&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这两种方式本质相同 —— 都是实时订阅链上数据变化。&lt;/p&gt;
&lt;p&gt;不同的是：&lt;strong&gt;gRPC 具备更好的类型安全与流控制能力&lt;/strong&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;二、准备环境&lt;/h2&gt;
&lt;p&gt;我们继续使用 &lt;code&gt;solana-go&lt;/code&gt; 库。&lt;/p&gt;
&lt;p&gt;依赖安装如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go get github.com/gagliardetto/solana-go@v1.11.0
go get github.com/gagliardetto/binary@v0.8.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;RPC 地址建议选择 &lt;strong&gt;Devnet 或自建节点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;RPC（HTTP/WSS）端点&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://api.devnet.solana.com
wss://api.devnet.solana.com
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;gRPC 端点（部分节点提供）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;grpc://api.devnet.solana.com:10000
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;三、监听类型概览&lt;/h2&gt;
&lt;p&gt;Solana 的事件订阅支持多种类型。&lt;/p&gt;
&lt;p&gt;常见监听类型如下表所示：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;监听类型&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;th&gt;常用场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Account Subscribe&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;监听指定账户数据变化&lt;/td&gt;
&lt;td&gt;监听钱包余额变动、NFT 元数据更新&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Logs Subscribe&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;监听指定 Program 的日志输出&lt;/td&gt;
&lt;td&gt;解析交易事件（如 Token Program 的 Transfer）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Program Subscribe&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;监听某个 Program 下所有账户变化&lt;/td&gt;
&lt;td&gt;建立索引器、同步 DApp 状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Signature Subscribe&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;监听交易签名状态变化&lt;/td&gt;
&lt;td&gt;等待交易确认或失败&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Slot Subscribe&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;监听新区块（Slot）&lt;/td&gt;
&lt;td&gt;实时获取最新区块高度&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Root Subscribe&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;监听已确认区块根&lt;/td&gt;
&lt;td&gt;追踪 Finalized 状态&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;四、使用 WebSocket 实现监听&lt;/h2&gt;
&lt;p&gt;我们先来看 &lt;strong&gt;最简单、最常见的方式&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;通过 WSS 订阅日志流。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;context&quot;
	&quot;fmt&quot;
	&quot;log&quot;

	&quot;github.com/gagliardetto/solana-go&quot;
	&quot;github.com/gagliardetto/solana-go/rpc&quot;
)

func main() {
	ctx := context.Background()

	//  连接 WSS
	client, err := rpc.ConnectWS(ctx, &quot;wss://api.devnet.solana.com&quot;)
	if err != nil {
		log.Fatalf(&quot;无法连接 WebSocket: %v&quot;, err)
	}

	//  订阅 Token Program 日志
	stream, err := client.LogsSubscribe(ctx, rpc.LogsSubscribeFilterMentions{
		Mentions: []solana.PublicKey{
			solana.MustPublicKeyFromBase58(&quot;TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA&quot;),
		},
	}, rpc.CommitmentFinalized)
	if err != nil {
		log.Fatalf(&quot;订阅失败: %v&quot;, err)
	}

	fmt.Println(&quot; 正在监听 Token Program 的日志...&quot;)

	//  实时接收
	for {
		msg, err := stream.Recv()
		if err != nil {
			log.Fatalf(&quot;接收失败: %v&quot;, err)
		}
		fmt.Printf(&quot; 区块 %d 日志:\n&quot;, msg.Context.Slot)
		for _, l := range msg.Value.Logs {
			fmt.Println(&quot;🪶&quot;, l)
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行后你会看到来自 Token Program 的实时日志输出：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;正在监听 Token Program 的日志...
 区块 31212400 日志:
🪶 Program log: Instruction: Transfer
🪶 Program log: Transfer 1000000 tokens
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就意味着，你的 Go 程序正在“听”整个 Solana 网络上的事件。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;五、通过 gRPC 订阅（生产级）&lt;/h2&gt;
&lt;p&gt;WSS 适合开发调试，但在&lt;strong&gt;高并发生产环境&lt;/strong&gt;下，&lt;/p&gt;
&lt;p&gt;gRPC 更加高效、安全，且支持强类型结构化数据。&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;solana-go&lt;/code&gt; 库中，我们可以这样实现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;context&quot;
	&quot;fmt&quot;
	&quot;log&quot;

	&quot;github.com/gagliardetto/solana-go&quot;
	&quot;github.com/gagliardetto/solana-go/rpc&quot;
)

func main() {
	ctx := context.Background()
	client := rpc.New(rpc.DevNet_RPC)

	stream, err := client.LogsSubscribe(ctx, rpc.LogsSubscribeFilterMentions{
		Mentions: []solana.PublicKey{
			solana.MustPublicKeyFromBase58(&quot;TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA&quot;),
		},
	}, rpc.CommitmentConfirmed)
	if err != nil {
		log.Fatalf(&quot;gRPC 订阅失败: %v&quot;, err)
	}

	fmt.Println(&quot; gRPC 实时监听中...&quot;)

	for {
		msg, err := stream.Recv()
		if err != nil {
			log.Fatalf(&quot;接收失败: %v&quot;, err)
		}
		fmt.Printf(&quot;[Slot %d] 日志数量: %d\n&quot;, msg.Context.Slot, len(msg.Value.Logs))
		for _, l := range msg.Value.Logs {
			fmt.Println(&quot;→&quot;, l)
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：部分 RPC 服务商（如 Helius、Triton）会开放专门的 gRPC 端点。&lt;/p&gt;
&lt;p&gt;建议生产系统接入这类服务，而非直接连接官方 Devnet。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;六、常见事件类型示例&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Program&lt;/th&gt;
&lt;th&gt;事件&lt;/th&gt;
&lt;th&gt;示例日志&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Token Program&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Transfer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Program log: Instruction: Transfer&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MintTo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Program log: Instruction: MintTo&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Burn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Program log: Instruction: Burn&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;System Program&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Transfer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Program log: Instruction: Transfer&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Metaplex NFT Program&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CreateMetadataAccount&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Program log: Instruction: CreateMetadataAccount&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UpdateMetadata&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Program log: Instruction: UpdateMetadata&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;七、结构化日志解析&lt;/h2&gt;
&lt;p&gt;日志虽然是字符串输出，但通过模式匹配或正则即可提取核心信息。&lt;/p&gt;
&lt;p&gt;例如，我们可以检测 &lt;code&gt;Instruction: Transfer&lt;/code&gt; 并捕获代币转账事件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if strings.Contains(line, &quot;Instruction: Transfer&quot;) {
	fmt.Println(&quot; 检测到转账事件！&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;生产系统中，可以进一步将日志解析为结构化 JSON，&lt;/p&gt;
&lt;p&gt;存入数据库或推送至 Kafka，供下游服务使用。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;八、监听账户变化（AccountSubscribe）&lt;/h2&gt;
&lt;p&gt;除了日志，开发者还可以直接监听某个账户的状态变化：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;stream, err := client.AccountSubscribe(ctx, walletAddress, &quot;&quot;, rpc.CommitmentConfirmed)
if err != nil {
	log.Fatalf(&quot;订阅账户失败: %v&quot;, err)
}
for {
	msg, err := stream.Recv()
	if err != nil {
		log.Fatal(&quot;接收失败:&quot;, err)
	}
	fmt.Println(&quot;账户余额更新:&quot;, msg.Value.Lamports)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当钱包收到或发送 SOL 时，程序会立即收到通知。&lt;/p&gt;
&lt;p&gt;这对于钱包类应用、收款服务尤其实用。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;九、生产环境最佳实践&lt;/h2&gt;
&lt;p&gt;在真实业务中，仅仅「打印日志」是不够的。&lt;/p&gt;
&lt;p&gt;以下是常见的生产架构思路：&lt;/p&gt;
&lt;h3&gt;1. 使用消息队列（MQ）&lt;/h3&gt;
&lt;p&gt;将事件推送到 Kafka / RabbitMQ / NATS，&lt;/p&gt;
&lt;p&gt;供其他微服务异步消费，避免阻塞主线程。&lt;/p&gt;
&lt;h3&gt;2. 增量存储&lt;/h3&gt;
&lt;p&gt;将已处理 Slot 记录到数据库中，&lt;/p&gt;
&lt;p&gt;确保应用重启后能从中断处恢复监听。&lt;/p&gt;
&lt;h3&gt;3. 多通道监听&lt;/h3&gt;
&lt;p&gt;同时监听多个 Program（Token、System、Metaplex），&lt;/p&gt;
&lt;p&gt;并根据类型路由到不同的处理逻辑。&lt;/p&gt;
&lt;h3&gt;4. gRPC + WebSocket 混合&lt;/h3&gt;
&lt;p&gt;在内部服务使用 gRPC 接口，&lt;/p&gt;
&lt;p&gt;对外提供标准化的 WebSocket 通知流，便于前端接入。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;十、练习与思考&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;使用 gRPC 监听 Token Program 的日志，统计过去 1 小时内的转账次数。&lt;/li&gt;
&lt;li&gt;将监听结果存入 PostgreSQL，并实现简单的区块索引。&lt;/li&gt;
&lt;li&gt;尝试监听特定钱包的 Token Account 变化，实现“到账提醒”。&lt;/li&gt;
&lt;li&gt;思考：如果要做一个 Solana 版的 Etherscan 监听模块，应该如何设计？&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;十一、小结&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;能力&lt;/th&gt;
&lt;th&gt;方法&lt;/th&gt;
&lt;th&gt;实现&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;实时监听日志&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LogsSubscribe()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;捕获链上 Program 输出&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;监听账户变化&lt;/td&gt;
&lt;td&gt;&lt;code&gt;AccountSubscribe()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;检测余额更新&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gRPC 流式订阅&lt;/td&gt;
&lt;td&gt;&lt;code&gt;client.LogsSubscribe()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;稳定高性能监听&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;稳定生产架构&lt;/td&gt;
&lt;td&gt;MQ + 增量同步&lt;/td&gt;
&lt;td&gt;实现可恢复监听系统&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded><author>Derick</author></item><item><title>Solana 指令与 Program 调用</title><link>https://blog.ithuo.net/posts/solana-program-invocation/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/solana-program-invocation/</guid><pubDate>Tue, 17 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;一、“智能合约”和“Program”的本质区别&lt;/h2&gt;
&lt;p&gt;在以太坊中，智能合约（Smart Contract）是部署在链上的字节码，&lt;/p&gt;
&lt;p&gt;每个用户可以调用它的函数。&lt;/p&gt;
&lt;p&gt;在 Solana 中，&lt;strong&gt;Program&lt;/strong&gt; 才是“智能合约”的概念。&lt;/p&gt;
&lt;p&gt;但它的运行方式有两点不同：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;对比项&lt;/th&gt;
&lt;th&gt;Ethereum&lt;/th&gt;
&lt;th&gt;Solana&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;执行环境&lt;/td&gt;
&lt;td&gt;EVM 虚拟机&lt;/td&gt;
&lt;td&gt;BPF 虚拟机&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;存储方式&lt;/td&gt;
&lt;td&gt;每个合约自带 Storage&lt;/td&gt;
&lt;td&gt;数据存储在独立 Account 中&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;调用方式&lt;/td&gt;
&lt;td&gt;调用函数名+参数&lt;/td&gt;
&lt;td&gt;传入指令（Instruction）+账户上下文&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;状态读写&lt;/td&gt;
&lt;td&gt;由合约自身维护&lt;/td&gt;
&lt;td&gt;由 Program 操作外部账户数据&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;换句话说，&lt;strong&gt;Solana 的 Program 是无状态的&lt;/strong&gt;，&lt;/p&gt;
&lt;p&gt;它需要外部账户作为“参数容器”来读写数据。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;二、理解 Solana 的 Instruction（指令）&lt;/h2&gt;
&lt;p&gt;Instruction 是链上执行的最小单元。&lt;/p&gt;
&lt;p&gt;它告诉验证节点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;调用哪个 Program（ProgramID）&lt;/li&gt;
&lt;li&gt;操作哪些账户（AccountMeta 列表）&lt;/li&gt;
&lt;li&gt;传入什么数据（Data，通常是序列化后的参数）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;其结构如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Instruction struct {
    Program  solana.PublicKey   // 被调用的程序ID
    Accounts []*AccountMeta     // 参与执行的账户
    Data     []byte             // 指令参数
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;示例：System Program 转账&lt;/h3&gt;
&lt;p&gt;System Program 是 Solana 内置的系统合约。&lt;/p&gt;
&lt;p&gt;我们在第二讲用它完成了转账，其实就是发送一条 &lt;code&gt;Transfer&lt;/code&gt; 指令。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;instruction := system.NewTransferInstruction(
    1_000_000_000,           // 转账 1 SOL
    sender.PublicKey(),      // 来源账户
    receiver.PublicKey(),    // 接收账户
).Build()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是一条最简单的 Program 调用。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;三、Solana 常见 Program 一览&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Program 名称&lt;/th&gt;
&lt;th&gt;Program ID&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;System Program&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;11111111111111111111111111111111&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;账户创建、转账&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Token Program (SPL Token)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;管理 SPL Token（类似 ERC-20）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Associated Token Program&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ATokenGPvotbQhHiTgJ7TGJ3TbxvucD8oCJeykT6tXk&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;生成 Token 账户&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Memo Program&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;写链上备注信息&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Stake Program&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Stake11111111111111111111111111111111111111&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;委托质押管理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compute Budget Program&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ComputeBudget111111111111111111111111111111&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;调整交易执行的资源预算&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;在实际开发中，我们经常需要和 &lt;strong&gt;Token Program&lt;/strong&gt; 或自定义 Program 进行交互。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;四、与 Memo Program 对话：最简单的 Program 调用&lt;/h2&gt;
&lt;p&gt;Memo Program 是 Solana 上的“Hello World”合约。&lt;/p&gt;
&lt;p&gt;它接收一段字符串，并将其记录在链上，供任何人查看。&lt;/p&gt;
&lt;p&gt;我们用 Go 调用它：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;context&quot;
	&quot;fmt&quot;
	&quot;log&quot;

	&quot;github.com/gagliardetto/solana-go&quot;
	&quot;github.com/gagliardetto/solana-go/programs/memo&quot;
	&quot;github.com/gagliardetto/solana-go/rpc&quot;
)

func main() {
	ctx := context.Background()
	client := rpc.New(rpc.DevNet_RPC)

	//  加载本地钱包
	sender, err := solana.PrivateKeyFromSolanaKeygenFile(&quot;/Users/alan/.config/solana/devnet.json&quot;)
	if err != nil {
		log.Fatalf(&quot;加载钱包失败: %v&quot;, err)
	}

	//  构造 Memo 指令
	instruction := memo.NewMemoInstruction(
		[]byte(&quot;Hello Solana from Go!&quot;),
	).Build()

	//  获取最新区块哈希
	recent, err := client.GetRecentBlockhash(ctx, rpc.CommitmentFinalized)
	if err != nil {
		log.Fatalf(&quot;获取区块哈希失败: %v&quot;, err)
	}

	//  创建交易
	tx, err := solana.NewTransaction(
		[]solana.Instruction{instruction},
		recent.Value.Blockhash,
		sender.PublicKey(),
	)
	if err != nil {
		log.Fatalf(&quot;创建交易失败: %v&quot;, err)
	}

	//  签名与发送
	_, err = tx.Sign(func(pub solana.PublicKey) *solana.PrivateKey {
		if pub.Equals(sender.PublicKey()) {
			return &amp;amp;sender
		}
		return nil
	})
	if err != nil {
		log.Fatalf(&quot;签名失败: %v&quot;, err)
	}

	sig, err := client.SendTransaction(ctx, tx)
	if err != nil {
		log.Fatalf(&quot;发送失败: %v&quot;, err)
	}

	fmt.Println(&quot; Memo 已上链，交易签名:&quot;, sig)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行完后，在 &lt;a href=&quot;https://explorer.solana.com/?cluster=devnet&quot;&gt;Solana Explorer (Devnet)&lt;/a&gt; 中搜索签名哈希，&lt;/p&gt;
&lt;p&gt;你能看到链上记录的那条 &lt;code&gt;&quot;Hello Solana from Go!&quot;&lt;/code&gt; 备注。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;五、账户元信息：AccountMeta&lt;/h2&gt;
&lt;p&gt;每条指令都需要声明哪些账户参与执行。&lt;/p&gt;
&lt;p&gt;这是 Solana 并行架构的关键，因为只有“互不重叠的账户”才能同时执行。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;AccountMeta&lt;/code&gt; 的定义如下：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;字段&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PublicKey&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;账户公钥&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;IsSigner&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;是否需要签名授权&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;IsWritable&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;是否可以被修改&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;meta := solana.NewAccountMeta(sender.PublicKey(), true, true)
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;记住：如果一个账户在指令中被标记为“写入”，&lt;/p&gt;
&lt;p&gt;它会被系统锁定，直到该交易执行结束。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;六、自定义指令数据的序列化&lt;/h2&gt;
&lt;p&gt;大多数自定义 Program 都需要传入特定格式的参数。&lt;/p&gt;
&lt;p&gt;Solana 的惯例是用 &lt;strong&gt;Borsh（Binary Object Representation Serializer for Hashing）&lt;/strong&gt; 序列化数据。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;solana-go&lt;/code&gt; 已内置 &lt;code&gt;binary&lt;/code&gt; 包支持：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import &quot;github.com/gagliardetto/binary&quot;

type MyInstruction struct {
	Action uint8
	Value  uint64
}

data, err := binary.Encode(struct {
	Action uint8
	Value  uint64
}{1, 42})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后将这段 &lt;code&gt;data&lt;/code&gt; 作为 Instruction 的 &lt;code&gt;Data&lt;/code&gt; 字段：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;instruction := solana.NewInstruction(
	myProgramID,
	accountMetaList...,
).SetData(data)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;七、组合多条指令执行（Batch Transaction）&lt;/h2&gt;
&lt;p&gt;在 Solana 中，一笔交易可以包含多条指令。&lt;/p&gt;
&lt;p&gt;例如我们可以先写入一条 Memo，再转账：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;instructions := []solana.Instruction{
	memo.NewMemoInstruction([]byte(&quot;Before transfer&quot;)).Build(),
	system.NewTransferInstruction(
		1_000_000,
		sender.PublicKey(),
		receiver.PublicKey(),
	).Build(),
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后像之前一样打包、签名、广播即可。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这让你能把多步操作打包成一次链上执行，大幅减少网络延迟与费用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;八、RPC 与 gRPC 调用的 Program 监听&lt;/h2&gt;
&lt;p&gt;在生产环境中，我们常常需要监听某个 Program 的事件。&lt;/p&gt;
&lt;p&gt;Solana 提供了 gRPC 流式订阅能力，非常适合链上服务。&lt;/p&gt;
&lt;h3&gt;订阅指定 Program 的日志输出&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;grpcClient := jsonrpc.NewClient(&quot;https://api.devnet.solana.com:443&quot;)
stream, err := grpcClient.SubscribeLogs(ctx, &quot;all&quot;, nil)
if err != nil {
	log.Fatalf(&quot;订阅失败: %v&quot;, err)
}

for {
	logs, err := stream.Recv()
	if err != nil {
		log.Fatalf(&quot;接收失败: %v&quot;, err)
	}
	fmt.Println(&quot;新的 Program 日志:&quot;, logs)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每当某个 Program 执行时，就会收到它的链上日志。&lt;/p&gt;
&lt;p&gt;这是做链上事件追踪或构建索引服务的核心手段。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;九、小结&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;模块&lt;/th&gt;
&lt;th&gt;内容&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;指令模型&lt;/td&gt;
&lt;td&gt;Program + Accounts + Data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;常见 Program&lt;/td&gt;
&lt;td&gt;System、Token、Memo、Stake&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Program 调用&lt;/td&gt;
&lt;td&gt;构造 → 序列化 → 签名 → 发送&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;账户元信息&lt;/td&gt;
&lt;td&gt;IsSigner / IsWritable 控制并发安全&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;调试方式&lt;/td&gt;
&lt;td&gt;gRPC 监听链上 Program 日志&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded><author>Derick</author></item><item><title>理解 SPL Token：Solana 的通用代币标准</title><link>https://blog.ithuo.net/posts/solana-spl-token-introduction/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/solana-spl-token-introduction/</guid><pubDate>Tue, 17 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;一、什么是 SPL Token？&lt;/h2&gt;
&lt;p&gt;在以太坊中，ERC-20 是最常见的代币标准。&lt;/p&gt;
&lt;p&gt;在 Solana 上，对应的标准是 &lt;strong&gt;SPL Token（Solana Program Library Token）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;SPL Token 并不是单个智能合约，而是一套系统标准，&lt;/p&gt;
&lt;p&gt;由一个官方 Program（Token Program）负责管理代币的生命周期。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;项目&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Program ID&lt;/td&gt;
&lt;td&gt;&lt;code&gt;TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;功能&lt;/td&gt;
&lt;td&gt;创建代币、铸造、转账、冻结、销毁&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;底层结构&lt;/td&gt;
&lt;td&gt;每个代币都有 Mint Account；每个持有人都有 Token Account&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;存储形式&lt;/td&gt;
&lt;td&gt;所有代币余额都存储在独立的账户数据中，而非 Program 内部&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;简单说：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mint Account&lt;/strong&gt; 是代币的定义（类似 ERC-20 合约）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Token Account&lt;/strong&gt; 是用户的余额存储位置。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;二、代币账户的结构&lt;/h2&gt;
&lt;p&gt;每种 SPL Token 都有一组对应的账户结构：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;类型&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mint Account&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;定义代币（总发行量、精度、小数位等）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Token Account&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;存储某个用户的代币余额&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Associated Token Account (ATA)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;系统推荐的 Token Account 生成方式，自动与用户钱包地址绑定&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;在实际开发中，我们几乎总是使用 ATA（Associated Token Account），&lt;/p&gt;
&lt;p&gt;因为它能确保每个钱包地址对同一种代币只有一个账户。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;三、准备工作&lt;/h2&gt;
&lt;p&gt;安装依赖：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go get github.com/gagliardetto/solana-go@v1.11.0
go get github.com/gagliardetto/binary@v0.8.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;设置环境：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;context&quot;
	&quot;fmt&quot;
	&quot;log&quot;

	&quot;github.com/gagliardetto/solana-go&quot;
	&quot;github.com/gagliardetto/solana-go/programs/associated-token-account&quot;
	&quot;github.com/gagliardetto/solana-go/programs/system&quot;
	&quot;github.com/gagliardetto/solana-go/programs/token&quot;
	&quot;github.com/gagliardetto/solana-go/rpc&quot;
)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;四、创建新代币（Mint）&lt;/h2&gt;
&lt;p&gt;以下代码展示如何在 &lt;strong&gt;Devnet&lt;/strong&gt; 上创建一个新代币（Mint Account）。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func main() {
	ctx := context.Background()
	client := rpc.New(rpc.DevNet_RPC)

	// 加载钱包（即代币创建者）
	creator, err := solana.PrivateKeyFromSolanaKeygenFile(&quot;/Users/alan/.config/solana/devnet.json&quot;)
	if err != nil {
		log.Fatalf(&quot;加载钱包失败: %v&quot;, err)
	}

	// 创建 Mint 账户（新代币定义）
	mint := solana.NewWallet()

	// 获取区块哈希
	recent, err := client.GetLatestBlockhash(ctx, rpc.CommitmentFinalized)
	if err != nil {
		log.Fatalf(&quot;获取哈希失败: %v&quot;, err)
	}

	//  构建交易
	tx, err := solana.NewTransaction(
		[]solana.Instruction{
			// 创建账户
			system.NewCreateAccountInstruction(
				2_039_280,                  // 租金
				token.MintAccountSize,      // 账户大小
				token.ProgramID,            // 所属 Program
				creator.PublicKey(),
				mint.PublicKey(),
			).Build(),

			// 初始化 Mint
			token.NewInitializeMint2Instruction(
				9,                  // 精度（小数位数）
				creator.PublicKey(), // 铸造权限
				nil,                 // 冻结权限（可选）
				mint.PublicKey(),    // Mint 地址
				token.ProgramID,
			).Build(),
		},
		recent.Value.Blockhash,
		creator.PublicKey(),
	)
	if err != nil {
		log.Fatalf(&quot;构建交易失败: %v&quot;, err)
	}

	// 签名并发送
	_, err = tx.Sign(func(pub solana.PublicKey) *solana.PrivateKey {
		switch {
		case pub.Equals(creator.PublicKey()):
			return &amp;amp;creator
		case pub.Equals(mint.PublicKey()):
			return &amp;amp;mint.PrivateKey
		default:
			return nil
		}
	})
	if err != nil {
		log.Fatalf(&quot;签名失败: %v&quot;, err)
	}

	sig, err := client.SendTransaction(ctx, tx)
	if err != nil {
		log.Fatalf(&quot;发送失败: %v&quot;, err)
	}

	fmt.Println(&quot;成功创建代币 Mint:&quot;, mint.PublicKey())
	fmt.Println(&quot;交易签名:&quot;, sig)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行后，你将拥有一个新的代币定义（Mint Account）。&lt;/p&gt;
&lt;p&gt;可以在 Solana Explorer 中搜索 &lt;code&gt;mint.PublicKey()&lt;/code&gt; 查看详情。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;五、创建持有人账户（Associated Token Account）&lt;/h2&gt;
&lt;p&gt;每个用户想要持有该代币，都需要一个 Token Account。&lt;/p&gt;
&lt;p&gt;使用 &lt;strong&gt;Associated Token Program&lt;/strong&gt; 可以自动生成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ata, _, err := associatedtokenaccount.GetAssociatedTokenAddress(
	creator.PublicKey(),  // 用户钱包地址
	mint.PublicKey(),     // 对应代币的 Mint 地址
)
if err != nil {
	log.Fatalf(&quot;生成 ATA 失败: %v&quot;, err)
}

instruction := associatedtokenaccount.NewCreateInstruction(
	creator.PublicKey(),  // 资助账户
	ata,                  // 目标 ATA
	creator.PublicKey(),  // 拥有者
	mint.PublicKey(),     // 代币
).Build()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;该指令会自动创建一个符合标准的代币账户。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意：&lt;/strong&gt; ATA 的地址是可预测的，因此无需存数据库。&lt;/p&gt;
&lt;p&gt;你随时可以通过同样方法计算出来。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;六、铸造代币（Mint To）&lt;/h2&gt;
&lt;p&gt;一旦 Mint 创建完成，就可以给任意账户“铸造”代币：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mintInstruction := token.NewMintToInstruction(
	mint.PublicKey(),     // 代币 Mint 地址
	ata,                  // 接收账户
	creator.PublicKey(),  // 铸造权限
	1_000_000_000,        // 数量（考虑精度）
).Build(
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再组合交易发送即可。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;七、查询余额&lt;/h2&gt;
&lt;p&gt;查询某个 Token Account 的余额，只需调用 RPC：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;balance, err := client.GetTokenAccountBalance(ctx, ata, rpc.CommitmentFinalized)
if err != nil {
	log.Fatalf(&quot;查询余额失败: %v&quot;, err)
}
fmt.Println(&quot; 当前余额:&quot;, balance.Value.UiAmountString)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;八、执行转账&lt;/h2&gt;
&lt;p&gt;Token Program 的 &lt;code&gt;Transfer&lt;/code&gt; 指令允许用户从一个 Token Account 向另一个账户发送代币：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;instruction := token.NewTransferInstruction(
	amount,               // 转账数量
	senderATA,            // 发送方代币账户
	receiverATA,          // 接收方代币账户
	sender.PublicKey(),   // 授权签名者
	nil,                  // 多签（可选）
	token.ProgramID,
).Build()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再像前面那样签名并广播。&lt;/p&gt;
&lt;p&gt;这与 System Program 的 SOL 转账几乎一致，只是多了 Token Account 参与。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;九、事件与监听（gRPC）&lt;/h2&gt;
&lt;p&gt;在生产环境中，我们通常需要监听某个 Mint 的交易事件。&lt;/p&gt;
&lt;p&gt;Solana 支持通过 &lt;strong&gt;gRPC 订阅日志流&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;stream, err := client.LogsSubscribe(ctx, rpc.LogsSubscribeFilterMentions{
    Mentions: []solana.PublicKey{token.ProgramID},
}, rpc.CommitmentFinalized)
if err != nil {
	log.Fatalf(&quot;订阅失败: %v&quot;, err)
}

for {
	msg, err := stream.Recv()
	if err != nil {
		log.Fatal(&quot;接收失败:&quot;, err)
	}
	fmt.Println(&quot; Token Program 日志:&quot;, msg.Value.Logs)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;通过这种方式，可以捕获任意代币的转账、铸造等链上事件。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;十、总结&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;内容&lt;/th&gt;
&lt;th&gt;概念&lt;/th&gt;
&lt;th&gt;示例函数&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;创建代币&lt;/td&gt;
&lt;td&gt;Mint Account&lt;/td&gt;
&lt;td&gt;&lt;code&gt;NewInitializeMint2Instruction&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;创建代币账户&lt;/td&gt;
&lt;td&gt;ATA&lt;/td&gt;
&lt;td&gt;&lt;code&gt;associatedtokenaccount.NewCreateInstruction&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;铸造代币&lt;/td&gt;
&lt;td&gt;Mint To&lt;/td&gt;
&lt;td&gt;&lt;code&gt;token.NewMintToInstruction&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;转账&lt;/td&gt;
&lt;td&gt;Token Transfer&lt;/td&gt;
&lt;td&gt;&lt;code&gt;token.NewTransferInstruction&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;查询余额&lt;/td&gt;
&lt;td&gt;RPC 调用&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GetTokenAccountBalance&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;事件监听&lt;/td&gt;
&lt;td&gt;gRPC 日志流&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LogsSubscribe&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded><author>Derick</author></item><item><title>深入理解Solana账户与交易机制</title><link>https://blog.ithuo.net/posts/solana-accounts-and-transactions/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/solana-accounts-and-transactions/</guid><pubDate>Thu, 12 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;一、为什么 Solana 的账户模型如此特别？&lt;/h2&gt;
&lt;p&gt;Solana 与 EVM 的最大不同，是&lt;strong&gt;账户不仅是资产容器，还是数据存储单元&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;它更像是一种“文件系统模型”，每个账户都是一个独立的文件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Program Account&lt;/strong&gt; —— 类似可执行文件（智能合约逻辑）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Account&lt;/strong&gt; —— 存储数据的账户，由特定程序控制读写权限。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;System Account&lt;/strong&gt; —— 系统级账户，用于创建新账户或转账 SOL。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在 Solana 上，一笔交易的执行过程更像是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“程序被加载进多个账户的上下文中，然后对其中的账户进行读写操作。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;二、账户的基本结构&lt;/h2&gt;
&lt;p&gt;每个账户在链上的核心字段如下：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;字段&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;lamports&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;账户余额，单位为 lamports（1 SOL = 1e9 lamports）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;owner&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;该账户由哪个 Program 拥有（例如 &lt;code&gt;SystemProgram&lt;/code&gt;）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;data&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;原始二进制数据，由程序自定义结构&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;executable&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;是否是可执行账户（即 Program）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;rentEpoch&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;租金周期，用于回收长期闲置账户&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;你可以理解为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“每个账户既能存钱，又能存数据，还能指定由谁来控制它。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;三、交易的三层结构：Transaction → Message → Instruction&lt;/h2&gt;
&lt;p&gt;Solana 的交易不是单条指令，而是一组“批处理操作”。&lt;/p&gt;
&lt;p&gt;它包含多个指令（Instruction），每条指令由一个 Program 执行。&lt;/p&gt;
&lt;h3&gt;1️⃣ Transaction&lt;/h3&gt;
&lt;p&gt;最外层结构，包含签名、公钥集合和消息。&lt;/p&gt;
&lt;h3&gt;2️⃣ Message&lt;/h3&gt;
&lt;p&gt;打包了一系列要执行的指令（Instructions），以及这些指令涉及的账户。&lt;/p&gt;
&lt;h3&gt;3️⃣ Instruction&lt;/h3&gt;
&lt;p&gt;单个操作，由：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Program ID&lt;/strong&gt;（哪个程序执行）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accounts&lt;/strong&gt;（涉及哪些账户）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data&lt;/strong&gt;（操作参数）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;整体结构如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Transaction
 └── Message
      ├── AccountKeys
      ├── RecentBlockhash
      └── Instructions[]
             ├── ProgramID
             ├── AccountIndices[]
             └── Data[]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;四、Solana 的签名机制&lt;/h2&gt;
&lt;p&gt;Solana 使用 &lt;strong&gt;Ed25519&lt;/strong&gt; 签名算法。&lt;/p&gt;
&lt;p&gt;每笔交易必须由至少一个签名者授权（通常是付款方的账户私钥）。&lt;/p&gt;
&lt;p&gt;签名的目标数据是 &lt;strong&gt;Message 的哈希&lt;/strong&gt;，而不是交易体。&lt;/p&gt;
&lt;p&gt;这样做的好处是可快速验证交易签名的正确性，且支持批量签名验证。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;简单来说：签名的是 Message，广播的是 Transaction。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;五、构造一笔转账交易（Go 实战）&lt;/h2&gt;
&lt;p&gt;现在我们通过 Go SDK 来构造并发送一笔简单的 SOL 转账。&lt;/p&gt;
&lt;h3&gt;导入依赖&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;import (
	&quot;context&quot;
	&quot;fmt&quot;
	&quot;log&quot;

	&quot;github.com/gagliardetto/solana-go&quot;
	&quot;github.com/gagliardetto/solana-go/rpc&quot;
	&quot;github.com/gagliardetto/solana-go/rpc/jsonrpc&quot;
	&quot;github.com/gagliardetto/solana-go/text&quot;
)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;构建核心逻辑&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func main() {
	ctx := context.Background()
	client := rpc.New(rpc.DevNet_RPC)

	// 1️⃣ 加载本地私钥（从 solana-keygen 生成的钱包）
	sender, err := solana.PrivateKeyFromSolanaKeygenFile(&quot;/Users/alan/.config/solana/devnet.json&quot;)
	if err != nil {
		log.Fatalf(&quot;加载钱包失败: %v&quot;, err)
	}

	receiver := solana.MustPublicKeyFromBase58(&quot;接收者钱包地址&quot;)

	// 2️⃣ 构造转账指令
	instruction := solana.NewInstruction(
		solana.SystemProgramID,
		solana.MustToAccountMeta(sender.PublicKey(), true, true),
		solana.MustToAccountMeta(receiver, false, true),
	).SetData(
		solana.MustEncodeSystemTransfer(
			solana.NewSystemTransferInstruction(
				sender.PublicKey(),
				receiver,
				1_000_000_000, // 转账 1 SOL = 1e9 lamports
			),
		),
	)

	// 3️⃣ 获取最新区块哈希
	recent, err := client.GetRecentBlockhash(ctx, rpc.CommitmentFinalized)
	if err != nil {
		log.Fatalf(&quot;获取区块哈希失败: %v&quot;, err)
	}

	// 4️⃣ 构造交易消息
	tx, err := solana.NewTransaction(
		[]solana.Instruction{instruction},
		recent.Value.Blockhash,
		sender.PublicKey(),
	)
	if err != nil {
		log.Fatalf(&quot;创建交易失败: %v&quot;, err)
	}

	// 5️⃣ 签名交易
	_, err = tx.Sign(func(key solana.PublicKey) *solana.PrivateKey {
		if sender.PublicKey().Equals(key) {
			return &amp;amp;sender
		}
		return nil
	})
	if err != nil {
		log.Fatalf(&quot;签名失败: %v&quot;, err)
	}

	// 6️⃣ 广播交易
	sig, err := client.SendTransaction(ctx, tx)
	if err != nil {
		log.Fatalf(&quot;广播失败: %v&quot;, err)
	}

	fmt.Println(&quot;✅ 交易已提交，签名哈希:&quot;, sig)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;六、用 Go 工具查看交易结构&lt;/h2&gt;
&lt;p&gt;SDK 提供了一个非常有用的调试工具 &lt;code&gt;text.NewEncoder()&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;encoder := text.NewEncoder(os.Stdout)
encoder.Encode(tx.Message)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输出结构大致如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Message {
  recent_blockhash: 7dMjeDkBmw6axbiTzA8npPQfLszDQAJhz3fWQ4XgG9b5
  account_keys: [
    1. Sender
    2. Receiver
    3. SystemProgram
  ]
  instructions: [
    0: Program(SystemProgram) -&amp;gt; Transfer 1 SOL
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这能帮助我们理解交易内部的账户引用关系，非常适合调试复杂合约调用。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;七、RPC 与 gRPC 接口的使用&lt;/h2&gt;
&lt;p&gt;Solana 节点支持两种交互方式：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;模式&lt;/th&gt;
&lt;th&gt;协议&lt;/th&gt;
&lt;th&gt;适合场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;JSON-RPC&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;HTTP(S)&lt;/td&gt;
&lt;td&gt;简单查询与交易提交&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;gRPC&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Binary over HTTP/2&lt;/td&gt;
&lt;td&gt;高并发、低延迟的链上同步与监听&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;在 Go SDK 中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rpc.New()&lt;/code&gt; → JSON-RPC 客户端&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jsonrpc.NewClient()&lt;/code&gt; → gRPC 模式客户端&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;例如，我们可以通过 gRPC 订阅区块事件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;grpcClient := jsonrpc.NewClient(&quot;https://api.devnet.solana.com:443&quot;)
stream, err := grpcClient.SubscribeSlotUpdates(ctx)
if err != nil {
	log.Fatalf(&quot;订阅失败: %v&quot;, err)
}

for {
	slotUpdate, err := stream.Recv()
	if err != nil {
		log.Fatalf(&quot;接收错误: %v&quot;, err)
	}
	fmt.Printf(&quot;新区块 Slot: %v\n&quot;, slotUpdate.Slot)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这种方式非常适合写区块监听器、价格同步服务等需要&lt;strong&gt;实时响应&lt;/strong&gt;的业务。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;八、小结&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;模块&lt;/th&gt;
&lt;th&gt;内容&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;账户模型&lt;/td&gt;
&lt;td&gt;通用账户体系、数据可存储与执行控制&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;交易结构&lt;/td&gt;
&lt;td&gt;Transaction → Message → Instruction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;签名机制&lt;/td&gt;
&lt;td&gt;Ed25519，对 Message 哈希签名&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Go 实战&lt;/td&gt;
&lt;td&gt;构造与发送转账交易&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;通信接口&lt;/td&gt;
&lt;td&gt;JSON-RPC + gRPC 双模式支持&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded><author>Derick</author></item><item><title>Solana 架构与开发环境搭建</title><link>https://blog.ithuo.net/posts/solana-tutorial-01-architecture-and-setup/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/solana-tutorial-01-architecture-and-setup/</guid><pubDate>Thu, 12 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;一、为什么选择 Solana？&lt;/h2&gt;
&lt;p&gt;如果说以太坊是“智能合约的起点”，&lt;/p&gt;
&lt;p&gt;那么 Solana 就是“高性能并行区块链的典范”。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;EVM 世界&lt;/strong&gt;：所有交易线性执行，TPS 通常低于 100。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Solana 世界&lt;/strong&gt;：通过 &lt;strong&gt;并行执行 (Parallel Execution)&lt;/strong&gt; 与 &lt;strong&gt;历史证明 (Proof of History, PoH)&lt;/strong&gt;，TPS 可轻松破万。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Solana 的理念是——&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“每一台计算机都能成为高频交易级的去中心化服务器。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这使得它在 DeFi、GameFi、NFT、L2 桥接等场景中表现极为出色。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;二、Solana 的整体架构&lt;/h2&gt;
&lt;p&gt;Solana 的底层架构由以下几个核心组件组成：&lt;/p&gt;
&lt;h3&gt;1. Validator（验证节点）&lt;/h3&gt;
&lt;p&gt;执行区块生成与交易验证。&lt;/p&gt;
&lt;p&gt;每个 Validator 都运行完整的链逻辑，包括账户存储与交易执行。&lt;/p&gt;
&lt;h3&gt;2. Leader 与 Slot&lt;/h3&gt;
&lt;p&gt;时间在 Solana 中被离散化为 &lt;strong&gt;Slot（时隙）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;每个 Slot 指派一个 &lt;strong&gt;Leader 节点&lt;/strong&gt; 负责产出区块。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1 Slot ≈ 400ms&lt;/li&gt;
&lt;li&gt;Leader 顺序由 PoH + PoS 混合机制决定&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. Proof of History（PoH）&lt;/h3&gt;
&lt;p&gt;PoH 是一种时间序列加密证明。&lt;/p&gt;
&lt;p&gt;它确保所有节点能就事件的顺序达成一致，而无需等待区块共识。&lt;/p&gt;
&lt;p&gt;这就是 Solana 能并行执行的关键。&lt;/p&gt;
&lt;h3&gt;4. Bank&lt;/h3&gt;
&lt;p&gt;每个 Bank 代表一个 Slot 的账户状态快照。&lt;/p&gt;
&lt;p&gt;所有交易都在 Bank 内执行，完成后生成下一个状态。&lt;/p&gt;
&lt;h3&gt;5. Account 模型&lt;/h3&gt;
&lt;p&gt;与 EVM 不同，Solana 没有“合约账户”和“外部账户”的区分，&lt;/p&gt;
&lt;p&gt;每个账户都可存储数据，并由特定 Program 控制。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;三、Solana 账户模型 vs Ethereum 账户模型&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;Ethereum&lt;/th&gt;
&lt;th&gt;Solana&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;账户类型&lt;/td&gt;
&lt;td&gt;EOA / Contract&lt;/td&gt;
&lt;td&gt;通用 Account&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;状态存储&lt;/td&gt;
&lt;td&gt;Storage&lt;/td&gt;
&lt;td&gt;Account Data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;执行入口&lt;/td&gt;
&lt;td&gt;&lt;code&gt;call&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Instruction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;余额单位&lt;/td&gt;
&lt;td&gt;Wei&lt;/td&gt;
&lt;td&gt;Lamports&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gas 模型&lt;/td&gt;
&lt;td&gt;gasPrice + gasLimit&lt;/td&gt;
&lt;td&gt;固定费率 + Rent 租金&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;日志机制&lt;/td&gt;
&lt;td&gt;Event Log&lt;/td&gt;
&lt;td&gt;Program Log&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Solana 的设计更加接近操作系统的概念——&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;账户像文件，Program 像系统调用&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;每个合约只是一个“可执行文件”，被多个账户共享使用。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;四、搭建本地开发环境&lt;/h2&gt;
&lt;p&gt;我们将搭建一个可运行的 Solana + Golang SDK 环境。&lt;/p&gt;
&lt;h3&gt;1️⃣ 安装 Solana CLI&lt;/h3&gt;
&lt;p&gt;Solana 官方 CLI 工具是与链交互的基础。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sh -c &quot;$(curl -sSfL https://release.solana.com/stable/install)&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装完成后，确认版本：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;solana --version
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;推荐版本：v1.18.0 及以上&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h3&gt;2️⃣ 配置开发网络&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;solana config set --url https://api.devnet.solana.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看当前配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;solana config get
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Devnet 是 Solana 的公共测试网络，数据可随时重置。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h3&gt;3️⃣ 创建钱包&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;solana-keygen new --outfile ~/.config/solana/devnet.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;设置默认钱包：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;solana config set --keypair ~/.config/solana/devnet.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看地址与余额：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;solana address
solana balance
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;请求测试代币空投/去Solana水龙头网点击获取：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;solana airdrop 2
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;4️⃣ 验证网络状态&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;solana validators
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看当前区块高度：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;solana slot
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;五、安装 Go SDK 环境&lt;/h2&gt;
&lt;p&gt;在 Go 环境中，我们使用 &lt;strong&gt;gagliardetto/solana-go&lt;/strong&gt; 作为主要 SDK。&lt;/p&gt;
&lt;h3&gt;初始化项目&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;mkdir solana-demo &amp;amp;&amp;amp; cd solana-demo
go mod init solana-demo
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;安装依赖&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;go get github.com/gagliardetto/solana-go@v1.11.0
go get github.com/gagliardetto/binary@v0.8.0
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;六、第一个 Solana 程序：查询账户余额&lt;/h2&gt;
&lt;p&gt;我们使用 Go SDK 查询刚创建的钱包余额。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;context&quot;
	&quot;fmt&quot;
	&quot;log&quot;

	&quot;github.com/gagliardetto/solana-go&quot;
	&quot;github.com/gagliardetto/solana-go/rpc&quot;
)

func main() {
	client := rpc.New(rpc.DevNet_RPC)
	ctx := context.Background()

	pubKey := solana.MustPublicKeyFromBase58(&quot;替换为你的公钥&quot;)

	balance, err := client.GetBalance(ctx, pubKey, rpc.CommitmentFinalized)
	if err != nil {
		log.Fatalf(&quot;查询失败: %v&quot;, err)
	}

	fmt.Printf(&quot;账户 %s 的余额为: %.9f SOL\n&quot;, pubKey, float64(balance.Value)/1e9)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go run main.go
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输出类似：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;账户 7X5T4T8FvDytM7Abz2uqegh6PqnsWWf29Rh7PGzFMp1u 的余额为: 2.000000000 SOL
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>Derick</author></item><item><title>构建事件索引系统</title><link>https://blog.ithuo.net/posts/blockchain-tutorial-evm-6/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/blockchain-tutorial-evm-6/</guid><pubDate>Sun, 08 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;目标：构建一个能在生产环境长期运行的链上事件索引器（indexer），把链上事件稳定、可验证地写入 PostgreSQL，并提供对外查询接口与重建能力。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;一、架构概览&lt;/h2&gt;
&lt;p&gt;核心组件：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Listener（实时订阅器）&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;通过 WSS 或 gRPC 订阅节点 &lt;code&gt;logs/newHeads/pending&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;把原始 &lt;code&gt;types.Log&lt;/code&gt; 转化为内部事件对象，放入可靠消息通道（本地内存队列或 Kafka/RabbitMQ）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Processor（解析与校验）&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;从消息通道消费事件，做 ABI 解码、字段规范化、合约白名单校验，生成要写入 DB 的 Domain 事件。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Writer（持久化层）&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;把事件写入 Postgres，在写入时保证幂等与顺序（使用唯一约束 + checkpoint）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Checkpoint 管理器&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;记录索引进度（例如已处理到的区块高度与区块哈希）。便于断点续跑与重建。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reorg Handler（重组处理）&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;检测区块重组/回滚，触发数据回滚或补偿逻辑，保证数据库与链上最终状态一致。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backfill Worker（历史索引器）&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;用于首次全量索引或补漏。按区块区间批量拉取 &lt;code&gt;eth_getLogs&lt;/code&gt; 或 &lt;code&gt;BlockByNumber&lt;/code&gt;，并将结果送入 Processor。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API / Query Layer&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;为上层应用提供查询接口（REST / GraphQL），支持分页、时间区间、按合约/事件类型过滤等。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Observability（监控 &amp;amp; 告警）&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;指标（Prometheus）、日志、分布式追踪（OpenTelemetry）、关键告警（处理延迟、错单、queue 泄漏、reorg 频发）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;架构图（文字版）：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Node（WSS/gRPC） → Listener → MessageQueue(Kafka/NSQ) → Processor → Writer(Postgres) ← CheckpointManager&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;另外：Backfill Worker 可直接读取 Node（HTTP）并写入 Processor；Reorg Handler 订阅 newHeads 并检测回滚。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;二、数据模型（PostgreSQL）—— 建表与索引&lt;/h2&gt;
&lt;p&gt;设计原则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;兼顾读取性能与写入吞吐；&lt;/li&gt;
&lt;li&gt;支持幂等写入与唯一约束；&lt;/li&gt;
&lt;li&gt;支持按合约/事件/区块区间快速查询；&lt;/li&gt;
&lt;li&gt;可扩展到多链/多环境。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关键表：&lt;/p&gt;
&lt;h3&gt;1. &lt;code&gt;blocks&lt;/code&gt; —— 区块头快照（Checkpoint 用）&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE blocks (
  block_number BIGINT PRIMARY KEY,
  block_hash TEXT NOT NULL,
  parent_hash TEXT NOT NULL,
  timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
  processed_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);
CREATE INDEX idx_blocks_timestamp ON blocks (timestamp);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. &lt;code&gt;raw_logs&lt;/code&gt; —— 原始日志（存储原始数据，便于审计）&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE raw_logs (
  id BIGSERIAL PRIMARY KEY,
  tx_hash TEXT NOT NULL,
  log_index INT NOT NULL,
  block_number BIGINT NOT NULL,
  block_hash TEXT NOT NULL,
  address TEXT NOT NULL,
  topics TEXT[],              -- jsonb/text array
  data BYTEA,
  received_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
  UNIQUE (tx_hash, log_index) -- 幂等保证
);
CREATE INDEX idx_raw_logs_block ON raw_logs (block_number);
CREATE INDEX idx_raw_logs_address ON raw_logs (address);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. &lt;code&gt;erc20_transfers&lt;/code&gt; —— 业务化事件表（示例）&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE erc20_transfers (
  id BIGSERIAL PRIMARY KEY,
  tx_hash TEXT NOT NULL,
  log_index INT NOT NULL,
  block_number BIGINT NOT NULL,
  block_hash TEXT NOT NULL,
  contract_address TEXT NOT NULL,
  from_address TEXT NOT NULL,
  to_address TEXT NOT NULL,
  amount NUMERIC(78,0) NOT NULL,
  processed_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
  UNIQUE (tx_hash, log_index) -- 再次保证幂等
);
CREATE INDEX idx_erc20_by_contract_block ON erc20_transfers (contract_address, block_number DESC);
CREATE INDEX idx_erc20_from_to ON erc20_transfers (from_address, to_address);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. &lt;code&gt;indexer_checkpoints&lt;/code&gt; —— 记录每个索引器进度&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE indexer_checkpoints (
  id TEXT PRIMARY KEY,       -- e.g., &quot;erc20_transfers_mainnet&quot;
  last_scanned_block BIGINT NOT NULL,
  last_scanned_block_hash TEXT NOT NULL,
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;raw_logs&lt;/code&gt; 用于存审计与回溯，保留原始 &lt;code&gt;topics&lt;/code&gt;、&lt;code&gt;data&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;每个业务事件表都以 &lt;code&gt;(tx_hash, log_index)&lt;/code&gt; 做唯一键，保证幂等插入；&lt;/li&gt;
&lt;li&gt;所有按区块查询的表需建立 &lt;code&gt;block_number&lt;/code&gt; 上的索引；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;blocks&lt;/code&gt; 表可用于快速比对区块哈希以检测 reorg。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;三、同步策略（实时 + 历史补齐）&lt;/h2&gt;
&lt;p&gt;系统通常需要两条工作流并行：&lt;/p&gt;
&lt;h3&gt;A. 实时流（Near real-time）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Listener 订阅 &lt;code&gt;logs&lt;/code&gt; / &lt;code&gt;newHeads&lt;/code&gt;，事件到达后先写入 &lt;code&gt;raw_logs&lt;/code&gt;（事务）→ Processor 解析并写入业务表 → 更新 checkpoint（小批量/事务内）。&lt;/li&gt;
&lt;li&gt;优点：低延迟，适合告警/即时业务触发。&lt;/li&gt;
&lt;li&gt;要点：保证消息处理顺序或可容忍乱序（用 &lt;code&gt;block_number&lt;/code&gt;+&lt;code&gt;log_index&lt;/code&gt;排序）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;B. 后向补齐（Backfill / Catch-up）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Backfill Worker 在部署或检测漏数据时，按区块区间 &lt;code&gt;from..to&lt;/code&gt; 使用 &lt;code&gt;eth_getLogs&lt;/code&gt; 或 &lt;code&gt;BlockByNumber&lt;/code&gt; 拉历史数据。&lt;/li&gt;
&lt;li&gt;写入同一套 Processor/Writer 流程，但需要保证不覆盖已存在数据（幂等检查）。&lt;/li&gt;
&lt;li&gt;对大区间建议分片并发拉取（例如每批 1000~5000 区块），并控制并发度以防节点限流。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实践建议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;实时流用于即时性；历史补齐用于首次索引或漏数据补偿。两者共享同一持久化 API，保证一致性。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;四、幂等、去重与顺序保证&lt;/h2&gt;
&lt;p&gt;生产系统的核心：&lt;strong&gt;绝对避免重复写入与乱序导致的数据不一致&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;策略：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;唯一约束（数据库级）&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;在 &lt;code&gt;raw_logs&lt;/code&gt; 与业务表上使用 &lt;code&gt;(tx_hash, log_index)&lt;/code&gt; 作为唯一键。写入失败（冲突）表示是重复消息，直接忽略或更新元信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;乐观并发控制（事务）&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;写入业务表时使用 DB 事务：先写 &lt;code&gt;raw_logs&lt;/code&gt;（若冲突则读取已有记录），再写业务表。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;消息幂等性&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;从消息队列消费时支持幂等处理：retry 不会导致重复数据（因为 DB 唯一约束会阻止）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;顺序保证&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;对于强顺序需求（比如需要严格按区块处理），可按 &lt;code&gt;block_number&lt;/code&gt; 分区单线程处理；或者采用 per-contract/key 的分区队列（sharding by contract address）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;示例：插入逻辑伪代码&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;BEGIN;
INSERT INTO raw_logs (tx_hash, log_index, ...) VALUES (...) ON CONFLICT (tx_hash, log_index) DO NOTHING;
-- 若原始记录已存在，可 fetch 确认是否已处理
INSERT INTO erc20_transfers (...)
  VALUES (...)
  ON CONFLICT (tx_hash, log_index) DO NOTHING;
-- 更新 checkpoint（原子/幂等）
COMMIT;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;五、重组（reorg）检测与处理&lt;/h2&gt;
&lt;p&gt;重组是链上需要认真对待的事实：短期内存在“临时被打包后又被替换”的区块。生产索引器需支持回滚与补偿。&lt;/p&gt;
&lt;h3&gt;重组检测思路（高层）：&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;在处理新区块 N 时，保存 &lt;code&gt;N-1&lt;/code&gt; 的哈希到 checkpoint。&lt;/li&gt;
&lt;li&gt;当新区块 M 到来，并且 &lt;code&gt;block.parent_hash != checkpoint.last_scanned_block_hash&lt;/code&gt;，说明发生重组或链顶回退。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;重组处理策略（两种常见方式）：&lt;/h3&gt;
&lt;h3&gt;A. 回滚并重放（safe, 保证一致）&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;找到 fork 的分叉点（从最新已知 checkpoint 向后比对区块哈希），确定需要回滚的区块范围 &lt;code&gt;[fork_block+1 .. last_scanned]&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;在 DB 中按 block_number 删除或标记这些区块对应的业务数据（并记录 tombstone 或历史）。&lt;/li&gt;
&lt;li&gt;将 checkpoint 回退到 &lt;code&gt;fork_block&lt;/code&gt;，然后重新从 &lt;code&gt;fork_block+1&lt;/code&gt; 按新区块顺序重放日志并写入数据。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;优点：数据最终一致；缺点：回滚代价高（可能删除大量数据），需保证回滚原子性并审计。&lt;/p&gt;
&lt;h3&gt;B. 乐观修补（复杂但更快）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;在检测到重组时，&lt;strong&gt;不立即回滚&lt;/strong&gt;，而把受到影响的区块/日志标注为 “可能不稳定（unfinalized）”。&lt;/li&gt;
&lt;li&gt;等待 &lt;code&gt;k&lt;/code&gt; 个确认（例如 12 或 30 个区块）后，才把区块标注为 &lt;code&gt;finalized&lt;/code&gt; 并执行写入/索引。&lt;/li&gt;
&lt;li&gt;如果发生重组且数据仍未 final，则直接忽略这些日志。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;优点：减少实际回滚操作（适合高吞吐业务）；缺点：增加延迟（需等待 confirmations）。&lt;/p&gt;
&lt;p&gt;推荐策略：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于高价值数据（余额、金融业务）采用 &lt;strong&gt;等待确认（confirmation）+在 DB 标注 finalized&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;对于实时通知可先入库并标注 &lt;code&gt;unfinalized&lt;/code&gt;，当确认数够后做 finalized 更新；若发生重组则做修正（回滚/修补）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实现细节：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在 &lt;code&gt;raw_logs&lt;/code&gt; 与业务表增加 &lt;code&gt;confirmed BOOLEAN DEFAULT false&lt;/code&gt;、&lt;code&gt;confirmations INT&lt;/code&gt; 字段。&lt;/li&gt;
&lt;li&gt;Listener 可维护 &lt;code&gt;last_final_block = latest_block - CONFIRMATION_DEPTH&lt;/code&gt;，并把 &lt;code&gt;block_number &amp;lt;= last_final_block&lt;/code&gt; 的记录打上 confirmed 标记。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;六、批处理与并发策略&lt;/h2&gt;
&lt;p&gt;吞吐与延迟的折中：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;批量写入&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;把多个事件合并成一个 DB 批插入（&lt;code&gt;COPY&lt;/code&gt; 或 &lt;code&gt;INSERT ... VALUES (...),(...),...&lt;/code&gt;），减少事务开销。&lt;/li&gt;
&lt;li&gt;批大小建议：几十到几百条，视 DB 性能与单条事件大小而定。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;并发分片&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;按 &lt;code&gt;contract_address % N&lt;/code&gt; 或 &lt;code&gt;block_number % N&lt;/code&gt; 做分片，分配给 N 个 Processor 实例并行处理。&lt;/li&gt;
&lt;li&gt;但要注意：同一合约的事件如果有顺序依赖，避免跨分片乱序。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;背压（Backpressure）&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;当数据库写入变慢时，应向 Listener 施加背压（暂停订阅或降低消费速率），避免内存 OOM 或消息堆积。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;幂等写入 + 可重复消费&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;设计使得任意消息可以被重复消费（幂等），便于重试与失败补偿。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;七、失败恢复与断点续跑&lt;/h2&gt;
&lt;p&gt;核心是&lt;strong&gt;Checkpoint&lt;/strong&gt;与&lt;strong&gt;幂等&lt;/strong&gt;两件事：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Checkpoint&lt;/strong&gt;：定期（或事务内）提交 &lt;code&gt;indexer_checkpoints&lt;/code&gt;，记录 &lt;code&gt;last_scanned_block&lt;/code&gt; 与 &lt;code&gt;block_hash&lt;/code&gt;。立即崩溃重启后，从该块后续开始。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;幂等写入&lt;/strong&gt;：若处理器重新消费已经处理过的日志，数据库唯一约束会阻止二次写入。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;补救流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;服务重启 → 读取 &lt;code&gt;indexer_checkpoints&lt;/code&gt; → 从 &lt;code&gt;last_scanned_block + 1&lt;/code&gt; 开始回放。&lt;/li&gt;
&lt;li&gt;Backfill Worker 可在发现缺漏时触发区块区间补填。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;八、监控与告警&lt;/h2&gt;
&lt;p&gt;必监控指标（Prometheus 推荐）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Listener 层：连接状态（connected/disconnected）、订阅错误率、WS/gRPC 重连次数。&lt;/li&gt;
&lt;li&gt;Queue：消费 lag（消息积压长度）、消费速率（msg/s）。&lt;/li&gt;
&lt;li&gt;Processor：每秒事件处理数、解码错误率、ABI 解析失败数。&lt;/li&gt;
&lt;li&gt;Writer/DB：写入延迟、批次大小、事务回滚/冲突次数、平均写入吞吐。&lt;/li&gt;
&lt;li&gt;Reorg：重组次数/小时、最长回滚深度（区块数）。&lt;/li&gt;
&lt;li&gt;健康：Last processed block number, last finalized block number。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;告警策略（示例）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;消费队列积压 &amp;gt; X（例如 10000） → 告警（可能处理慢或节点限流）。&lt;/li&gt;
&lt;li&gt;Listener disconnect &amp;gt; 5 次 / 10 min → 告警。&lt;/li&gt;
&lt;li&gt;Reorg 深度 &amp;gt; K（例如 10） → 告警并人工介入。&lt;/li&gt;
&lt;li&gt;最近处理区块落后链高度超过 Y（例如 500） → 告警。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;日志与追踪：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每条事件处理应打 trace id（tx_hash）以便追踪全链路。使用 OpenTelemetry / Jaeger 做分布式追踪。&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Derick</author></item><item><title>解剖交易 —— 从调用到事件日志</title><link>https://blog.ithuo.net/posts/blockchain-tutorial-evm-4/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/blockchain-tutorial-evm-4/</guid><pubDate>Sun, 08 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;“交易，是以太坊的语言。&lt;/p&gt;
&lt;p&gt;它让世界状态从一个快照跃迁到另一个快照。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;一、从区块到交易：事件的起点&lt;/h2&gt;
&lt;p&gt;还记得上一讲我们获取到的区块结构吗？&lt;/p&gt;
&lt;p&gt;每个区块其实就是一个“交易集合”。&lt;/p&gt;
&lt;p&gt;这些交易可能是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;转账（账户对账户）&lt;/li&gt;
&lt;li&gt;部署智能合约（合约创建）&lt;/li&gt;
&lt;li&gt;调用智能合约函数（执行逻辑）&lt;/li&gt;
&lt;li&gt;内部合约间调用（子交易）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;换句话说，&lt;strong&gt;交易是状态变化的唯一通道&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;在传统后端系统中，我们可能有“HTTP 请求”触发数据库操作；&lt;/p&gt;
&lt;p&gt;而在以太坊上，&lt;strong&gt;交易就是那次请求&lt;/strong&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;二、交易的生命周期：从签名到上链&lt;/h2&gt;
&lt;p&gt;我们先来理解“交易”这件事到底经历了什么。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;阶段&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;th&gt;类比&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1️⃣ 创建 (Create)&lt;/td&gt;
&lt;td&gt;用户或合约发起一笔交易&lt;/td&gt;
&lt;td&gt;构造 HTTP 请求&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2️⃣ 签名 (Sign)&lt;/td&gt;
&lt;td&gt;使用私钥签名，确保来源可信&lt;/td&gt;
&lt;td&gt;用 Token 认证请求&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3️⃣ 广播 (Broadcast)&lt;/td&gt;
&lt;td&gt;交易被节点传播到全网&lt;/td&gt;
&lt;td&gt;将请求提交给网关&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4️⃣ 打包 (Include)&lt;/td&gt;
&lt;td&gt;矿工/验证者将交易收入区块&lt;/td&gt;
&lt;td&gt;请求被后端服务处理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5️⃣ 执行 (Execute)&lt;/td&gt;
&lt;td&gt;EVM 执行代码、修改状态&lt;/td&gt;
&lt;td&gt;执行数据库操作&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6️⃣ 生成收据 (Receipt)&lt;/td&gt;
&lt;td&gt;节点记录执行结果、日志&lt;/td&gt;
&lt;td&gt;返回 API 响应&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这其中最关键的两个对象是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Transaction&lt;/strong&gt;：交易的原始请求体。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Receipt&lt;/strong&gt;：执行结束后的“回执”，包含结果与日志。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;三、目标：通过 Go 获取一笔交易及其收据&lt;/h2&gt;
&lt;p&gt;我们将使用 Go 语言完成以下操作：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;获取一笔交易（通过交易哈希）&lt;/li&gt;
&lt;li&gt;查看其发送方、接收方、Gas 信息等&lt;/li&gt;
&lt;li&gt;获取交易收据，判断是否执行成功&lt;/li&gt;
&lt;li&gt;读取交易产生的事件日志（Logs）&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;四、实战：解剖一笔交易&lt;/h2&gt;
&lt;p&gt;创建文件 &lt;code&gt;tx_inspect.go&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;context&quot;
	&quot;fmt&quot;
	&quot;log&quot;

	&quot;github.com/ethereum/go-ethereum/common&quot;
	&quot;github.com/ethereum/go-ethereum/ethclient&quot;
)

func main() {
	// 1. 连接以太坊节点
	client, err := ethclient.Dial(&quot;https://sepolia.infura.io/v3/&amp;lt;YOUR_PROJECT_ID&amp;gt;&quot;)
	if err != nil {
		log.Fatalf(&quot;连接节点失败: %v&quot;, err)
	}
	defer client.Close()

	// 2. 准备要查询的交易哈希
	txHash := common.HexToHash(&quot;0xYOUR_TX_HASH_HERE&quot;) // 替换为真实哈希

	// 3. 查询交易详情
	tx, isPending, err := client.TransactionByHash(context.Background(), txHash)
	if err != nil {
		log.Fatalf(&quot;无法获取交易信息: %v&quot;, err)
	}

	fmt.Println(&quot;———————— 交易详情 ————————&quot;)
	fmt.Printf(&quot;交易哈希: %v\n&quot;, tx.Hash().Hex())
	fmt.Printf(&quot;是否未确认(Pending): %v\n&quot;, isPending)
	fmt.Printf(&quot;Nonce: %v\n&quot;, tx.Nonce())
	fmt.Printf(&quot;GasLimit: %v\n&quot;, tx.Gas())
	fmt.Printf(&quot;Value (ETH): %v\n&quot;, tx.Value())

	// 4. 获取交易收据（执行结果）
	receipt, err := client.TransactionReceipt(context.Background(), txHash)
	if err != nil {
		log.Fatalf(&quot;无法获取交易收据: %v&quot;, err)
	}

	fmt.Println(&quot;———————— 收据信息 ————————&quot;)
	fmt.Printf(&quot;区块号: %v\n&quot;, receipt.BlockNumber)
	fmt.Printf(&quot;交易状态: %v\n&quot;, receipt.Status)
	fmt.Printf(&quot;Gas 消耗: %v\n&quot;, receipt.GasUsed)
	fmt.Printf(&quot;事件日志数量: %d\n&quot;, len(receipt.Logs))

	// 5. 打印日志详情
	if len(receipt.Logs) &amp;gt; 0 {
		fmt.Println(&quot;———————— 第一条事件日志 ————————&quot;)
		log := receipt.Logs[0]
		fmt.Printf(&quot;合约地址: %v\n&quot;, log.Address.Hex())
		fmt.Printf(&quot;主题数量: %d\n&quot;, len(log.Topics))
		fmt.Printf(&quot;原始数据: %x\n&quot;, log.Data)
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go run tx_inspect.go
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果一切正常，你将看到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;———————— 交易详情 ————————
交易哈希: 0x8b2f...
是否未确认(Pending): false
Nonce: 12
GasLimit: 21000
Value (ETH): 1000000000000000000
———————— 收据信息 ————————
区块号: 5689012
交易状态: 1
Gas 消耗: 21000
事件日志数量: 0
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;💡 状态码说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1&lt;/code&gt; 表示执行成功&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0&lt;/code&gt; 表示执行失败（可能是合约异常或 gas 不足）&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;五、事件日志（Logs）：智能合约的“回声”&lt;/h2&gt;
&lt;p&gt;如果交易是“调用”，那么事件日志就是它的“回声”。&lt;/p&gt;
&lt;p&gt;每当智能合约执行 &lt;code&gt;emit&lt;/code&gt; 操作（如 &lt;code&gt;emit Transfer(...)&lt;/code&gt;），&lt;/p&gt;
&lt;p&gt;EVM 都会在交易收据中生成一条 &lt;strong&gt;Log&lt;/strong&gt;。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;字段&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;address&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;产生事件的合约地址&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;topics&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;事件主题（Indexed 参数）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;非索引参数的原始数据&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;一个典型的 ERC20 转账事件如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;event Transfer(address indexed from, address indexed to, uint256 value);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行时会生成一条日志，&lt;/p&gt;
&lt;p&gt;其 &lt;code&gt;topics[0]&lt;/code&gt; 存放事件签名哈希，&lt;/p&gt;
&lt;p&gt;&lt;code&gt;topics[1]&lt;/code&gt; 与 &lt;code&gt;topics[2]&lt;/code&gt; 分别是 &lt;code&gt;from&lt;/code&gt;、&lt;code&gt;to&lt;/code&gt; 地址，&lt;/p&gt;
&lt;p&gt;&lt;code&gt;data&lt;/code&gt; 部分存放转账金额。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“当你学会看懂一笔交易的执行过程，&lt;/p&gt;
&lt;p&gt;你就不再是观察区块链的人，&lt;/p&gt;
&lt;p&gt;而是理解它的那个人。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;六、延伸练习：从日志到真相&lt;/h2&gt;
&lt;p&gt;在上面的章节中，我们学会了获取交易收据（&lt;code&gt;Receipt&lt;/code&gt;），知道它是合约执行后的“回执”。&lt;/p&gt;
&lt;p&gt;但如果只停留在打印状态，我们还离真正的理解差一步。&lt;/p&gt;
&lt;p&gt;接下来这三组练习，会让你从不同角度看透链上执行的全貌。&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;练习 1：解析 ERC20 转账事件（Transfer）&lt;/h3&gt;
&lt;p&gt;几乎所有的代币转账，都会触发一个标准事件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;event Transfer(address indexed from, address indexed to, uint256 value);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它是 ERC20 标准中最重要的信号之一——代表“从哪转到哪，转了多少”。&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;🧠 背后的机制：&lt;/h3&gt;
&lt;p&gt;每当合约执行 &lt;code&gt;emit Transfer(...)&lt;/code&gt;，EVM 就会将这条事件日志写入收据中的 &lt;code&gt;logs&lt;/code&gt; 字段。&lt;/p&gt;
&lt;p&gt;这个日志并不是可执行代码，而是一段结构化的“广播消息”。&lt;/p&gt;
&lt;p&gt;每条日志由以下部分组成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;address&lt;/code&gt;：事件来源（合约地址）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;topics[]&lt;/code&gt;：索引字段（indexed 参数）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;data&lt;/code&gt;：非索引字段（普通参数）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;例如，对于上面的 &lt;code&gt;Transfer&lt;/code&gt; 事件：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;参数&lt;/th&gt;
&lt;th&gt;存放位置&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;from&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;topics[1]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;to&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;topics[2]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;value&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;data&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h3&gt;🧩 实践目标：&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;在测试网（如 Sepolia）选择一个 ERC20 代币（例如 DAI 或 USDC）。&lt;/li&gt;
&lt;li&gt;使用上一讲的 &lt;code&gt;TransactionReceipt&lt;/code&gt; 方法，获取收据的 &lt;code&gt;Logs&lt;/code&gt; 字段。&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;go-ethereum/accounts/abi&lt;/code&gt; 模块解析日志。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;import &quot;github.com/ethereum/go-ethereum/accounts/abi&quot;

erc20Abi, _ := abi.JSON(strings.NewReader(`[{&quot;anonymous&quot;:false,&quot;inputs&quot;:[
	{&quot;indexed&quot;:true,&quot;name&quot;:&quot;from&quot;,&quot;type&quot;:&quot;address&quot;},
	{&quot;indexed&quot;:true,&quot;name&quot;:&quot;to&quot;,&quot;type&quot;:&quot;address&quot;},
	{&quot;indexed&quot;:false,&quot;name&quot;:&quot;value&quot;,&quot;type&quot;:&quot;uint256&quot;}
],&quot;name&quot;:&quot;Transfer&quot;,&quot;type&quot;:&quot;event&quot;}]`))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过 &lt;code&gt;UnpackIntoInterface()&lt;/code&gt; 解析 &lt;code&gt;vLog.Data&lt;/code&gt;，即可获取转账金额。&lt;/p&gt;
&lt;p&gt;同时，&lt;code&gt;vLog.Topics[1]&lt;/code&gt;、&lt;code&gt;vLog.Topics[2]&lt;/code&gt; 分别对应发送方与接收方地址。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;✅ 当你能打印出 “From → To : Value” 的信息时，&lt;/p&gt;
&lt;p&gt;你就完成了第一次事件解析任务。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h3&gt;练习 2：追踪失败交易（Transaction Failure）&lt;/h3&gt;
&lt;p&gt;区块链的交易，并不是每次都会成功。&lt;/p&gt;
&lt;p&gt;智能合约可能因为条件不满足、余额不足、或显式调用 &lt;code&gt;revert()&lt;/code&gt; 而失败。&lt;/p&gt;
&lt;p&gt;这类失败不会被节点“撤销”或“回滚”，&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;它仍然会被打包进区块，只是结果标记为失败。&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;🧠 观察要点：&lt;/h3&gt;
&lt;p&gt;在交易收据中，有一个非常关键的字段：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;receipt.Status // 1 表示成功，0 表示失败
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当 &lt;code&gt;Status == 0&lt;/code&gt; 时，说明该交易执行失败。&lt;/p&gt;
&lt;p&gt;这时，&lt;code&gt;Logs&lt;/code&gt; 通常为空，因为合约内部的事件也被回滚。&lt;/p&gt;
&lt;p&gt;而 &lt;code&gt;GasUsed&lt;/code&gt; 依然存在——因为即便失败，也要支付执行成本。&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;🧩 实践建议：&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;选择一笔失败的交易（可在区块浏览器中找到标红的交易）。&lt;/li&gt;
&lt;li&gt;用 &lt;code&gt;client.TransactionReceipt(context, hash)&lt;/code&gt; 获取其收据。&lt;/li&gt;
&lt;li&gt;打印出以下关键信息：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;fmt.Printf(&quot;Status: %d\nGasUsed: %d\nLogsCount: %d\n&quot;,
	receipt.Status,
	receipt.GasUsed,
	len(receipt.Logs))
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;尝试理解为什么会失败（可以在 Etherscan 的 “Input Data” 区块中查看合约调用参数）。&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;💡 小提示：&lt;/p&gt;
&lt;p&gt;在失败的交易中，EVM 会抛出 &lt;code&gt;REVERT&lt;/code&gt; 异常，&lt;/p&gt;
&lt;p&gt;但返回的数据仍然可以通过 debug trace 或模拟执行获取。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h3&gt;练习 3：批量扫描区块交易（Block Scan）&lt;/h3&gt;
&lt;p&gt;到目前为止，我们都是通过交易哈希直接获取收据。&lt;/p&gt;
&lt;p&gt;但如果我们想要“扫整条链”，该怎么办？&lt;/p&gt;
&lt;p&gt;最直接的办法，就是批量遍历区块。&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;🧩 实践目标：&lt;/h3&gt;
&lt;p&gt;编写一段程序，从最新区块开始向前遍历：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用 &lt;code&gt;client.BlockByNumber()&lt;/code&gt; 获取区块；&lt;/li&gt;
&lt;li&gt;读取 &lt;code&gt;block.Transactions()&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;对每个交易调用 &lt;code&gt;TransactionReceipt()&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;输出交易状态、Gas 消耗等信息。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h3&gt;💻 伪代码示例：&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;for i := startBlock; i &amp;gt; startBlock-10; i-- {
	block, _ := client.BlockByNumber(ctx, big.NewInt(int64(i)))
	fmt.Printf(&quot;区块 #%d 包含 %d 笔交易\n&quot;, i, len(block.Transactions()))

	for _, tx := range block.Transactions() {
		receipt, _ := client.TransactionReceipt(ctx, tx.Hash())
		fmt.Printf(&quot;- Tx %s | Status: %d | GasUsed: %d\n&quot;,
			tx.Hash().Hex(), receipt.Status, receipt.GasUsed)
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;🚀 当你能批量遍历并打印交易结果时，&lt;/p&gt;
&lt;p&gt;你就完成了“扫链”的最基础形态。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;七、幕后机制：Receipt 的诞生之路&lt;/h2&gt;
&lt;p&gt;我们现在来揭开 &lt;code&gt;Receipt&lt;/code&gt;（交易回执）背后的运行原理。&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;1️⃣ EVM 执行阶段&lt;/h3&gt;
&lt;p&gt;当一笔交易进入区块后，节点会执行以下步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;加载账户与合约状态&lt;/strong&gt;（从状态树中读取）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;执行字节码&lt;/strong&gt;（EVM 逐条运行 opcode）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;记录执行日志&lt;/strong&gt;（Log、Gas 消耗、中间状态）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生成 Receipt&lt;/strong&gt;（包含执行结果）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Receipt 的结构体大致如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Receipt struct {
	Status            uint64
	CumulativeGasUsed uint64
	Logs              []*Log
	TxHash            common.Hash
	BlockHash         common.Hash
	BlockNumber       *big.Int
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;2️⃣ 写入 Merkle Trie&lt;/h3&gt;
&lt;p&gt;每个区块执行完所有交易后，节点会：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;把所有 &lt;code&gt;Receipt&lt;/code&gt; 的哈希插入一个 &lt;strong&gt;Merkle Trie&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;将这个 Trie 的根哈希（&lt;code&gt;receiptsRoot&lt;/code&gt;）写入区块头。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这就意味着：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;如果任何一个交易的收据被篡改，&lt;/p&gt;
&lt;p&gt;整个 Merkle 根都会变化，&lt;/p&gt;
&lt;p&gt;因此所有节点都会立即检测到不一致。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h3&gt;3️⃣ 强一致性的保证&lt;/h3&gt;
&lt;p&gt;这正是以太坊“世界计算机”的奥义所在：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;每个节点独立执行相同交易 → 得到相同的状态树根与收据树根。&lt;/p&gt;
&lt;p&gt;区块头包含这两个根 → 保证链上结果不可伪造。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这就是所谓的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Deterministic Execution + Merkle Proof = Trustless Finality&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;没有人能篡改结果，也没人能偷偷修改日志。&lt;/p&gt;
&lt;p&gt;任何状态的正确性，都能被其他节点独立验证。&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;4️⃣ 一个简单的类比&lt;/h3&gt;
&lt;p&gt;你可以把 Receipt 想象成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;交易&lt;/strong&gt; 是数据库的事务；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Receipt&lt;/strong&gt; 是事务的提交日志；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Merkle Trie&lt;/strong&gt; 是写入分布式账本的“哈希索引”。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，当你在浏览器上看到“交易成功”这几个字时，&lt;/p&gt;
&lt;p&gt;其实背后是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;EVM 执行完 → 状态树更新 → 收据写入 Trie → 区块头签名 → 广播全网确认。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这一连串动作，全世界的节点都在同步执行。&lt;/p&gt;
&lt;p&gt;而你的本地客户端，只是去&lt;strong&gt;读取那份共识结果&lt;/strong&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;🧩 总结&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;知识点&lt;/th&gt;
&lt;th&gt;关键理解&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ERC20 Transfer 日志&lt;/td&gt;
&lt;td&gt;合约通过事件广播状态变化&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;交易失败状态&lt;/td&gt;
&lt;td&gt;Status=0 仍会上链，Gas 不退还&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;批量区块扫描&lt;/td&gt;
&lt;td&gt;是扫链与索引系统的基础&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Receipt 结构&lt;/td&gt;
&lt;td&gt;包含执行状态、Gas、事件等信息&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Merkle Trie&lt;/td&gt;
&lt;td&gt;保证收据与状态的一致性与不可篡改性&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;p&gt;“Receipt 不只是交易的收据，&lt;/p&gt;
&lt;p&gt;它是以太坊‘世界共识’的证明。&lt;/p&gt;
&lt;p&gt;每一份收据，都是一段可验证的历史。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
</content:encoded><author>Derick</author></item><item><title>监听事件 —— 让你的程序实时感知区块链的脉搏</title><link>https://blog.ithuo.net/posts/blockchain-tutorial-evm-5/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/blockchain-tutorial-evm-5/</guid><pubDate>Sun, 08 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;“查询让我们理解过去，&lt;/p&gt;
&lt;p&gt;监听让我们捕捉现在。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;一、为什么要监听区块链事件？&lt;/h2&gt;
&lt;p&gt;在区块链世界中，每一笔交易、每一次合约调用、每一个新区块的产生&lt;/p&gt;
&lt;p&gt;都代表着&lt;strong&gt;状态的改变&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;如果我们只依赖 HTTP 方式去轮询（polling）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for {
    latestBlock, _ := client.BlockByNumber(ctx, nil)
    fmt.Println(latestBlock.Number())
    time.Sleep(time.Second * 5)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;——这虽然能工作，但效率极低、延迟高，还容易漏数据。&lt;/p&gt;
&lt;p&gt;所以，Ethereum 节点提供了“推送式”的交互接口：&lt;/p&gt;
&lt;p&gt;当区块或日志变化时，节点&lt;strong&gt;主动通知&lt;/strong&gt;客户端。&lt;/p&gt;
&lt;p&gt;这正是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;事件监听（Event Subscription）机制&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;二、两种监听通道：WSS 与 gRPC&lt;/h2&gt;
&lt;h3&gt;1. WebSocket 模式（最常用）&lt;/h3&gt;
&lt;p&gt;特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基于 &lt;code&gt;eth_subscribe&lt;/code&gt; RPC 机制；&lt;/li&gt;
&lt;li&gt;通信协议是 &lt;code&gt;wss://&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;节点会主动推送事件；&lt;/li&gt;
&lt;li&gt;适用于 DApp 后端、监控、通知等。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;典型 URL：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wss://mainnet.infura.io/ws/v3/&amp;lt;YOUR_PROJECT_ID&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;2. gRPC 模式（底层流式接口）&lt;/h3&gt;
&lt;p&gt;gRPC 模式是 go-ethereum 在 1.10+ 版本后提供的另一套接口，&lt;/p&gt;
&lt;p&gt;它通过 Protocol Buffers 定义数据结构，&lt;/p&gt;
&lt;p&gt;实现&lt;strong&gt;更高性能的实时流式订阅&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;二进制通信（比 JSON-RPC 快 3~5 倍）；&lt;/li&gt;
&lt;li&gt;支持原生流式调用（stream）；&lt;/li&gt;
&lt;li&gt;适合高并发、低延迟的企业级系统；&lt;/li&gt;
&lt;li&gt;节点需以 &lt;code&gt;-grpc&lt;/code&gt; 启动。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;典型 URL：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;grpc://127.0.0.1:8545
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;三、监听类型总览&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;监听类型&lt;/th&gt;
&lt;th&gt;函数（go-ethereum）&lt;/th&gt;
&lt;th&gt;适用通道&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;新区块&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SubscribeNewHead()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;WSS/gRPC&lt;/td&gt;
&lt;td&gt;监听新产生的区块头&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;合约事件&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SubscribeFilterLogs()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;WSS/gRPC&lt;/td&gt;
&lt;td&gt;监听智能合约日志&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;待确认交易&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SubscribePendingTransactions()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;WSS&lt;/td&gt;
&lt;td&gt;监听交易池中的交易&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;同步状态&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SubscribeSyncing()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;WSS/gRPC&lt;/td&gt;
&lt;td&gt;监听节点同步进度&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;历史日志&lt;/td&gt;
&lt;td&gt;&lt;code&gt;FilterLogs()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;HTTP/WSS&lt;/td&gt;
&lt;td&gt;拉取过去区块的事件&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;四、WSS 模式实战&lt;/h2&gt;
&lt;h3&gt;示例 1：监听新区块&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;context&quot;
	&quot;fmt&quot;
	&quot;log&quot;

	&quot;github.com/ethereum/go-ethereum/core/types&quot;
	&quot;github.com/ethereum/go-ethereum/ethclient&quot;
)

func main() {
	client, err := ethclient.Dial(&quot;wss://sepolia.infura.io/ws/v3/YOUR_PROJECT_ID&quot;)
	if err != nil {
		log.Fatalf(&quot;❌ 无法连接节点: %v&quot;, err)
	}
	defer client.Close()

	headers := make(chan *types.Header)
	sub, err := client.SubscribeNewHead(context.Background(), headers)
	if err != nil {
		log.Fatalf(&quot;❌ 订阅失败: %v&quot;, err)
	}

	fmt.Println(&quot;✅ 正在监听新区块事件...&quot;)
	for {
		select {
		case err := &amp;lt;-sub.Err():
			log.Println(&quot;⚠️ 订阅错误:&quot;, err)
		case header := &amp;lt;-headers:
			fmt.Printf(&quot;⛓️ 新区块 #%v | 哈希: %s\n&quot;, header.Number, header.Hash())
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输出示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;✅ 正在监听新区块事件...
⛓️ 新区块 #5862145 | 哈希: 0x9e1234...
⛓️ 新区块 #5862146 | 哈希: 0xbca987...
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;示例 2：监听合约事件（Transfer）&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;context&quot;
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;math/big&quot;
	&quot;strings&quot;

	&quot;github.com/ethereum/go-ethereum&quot;
	&quot;github.com/ethereum/go-ethereum/accounts/abi&quot;
	&quot;github.com/ethereum/go-ethereum/common&quot;
	&quot;github.com/ethereum/go-ethereum/core/types&quot;
	&quot;github.com/ethereum/go-ethereum/ethclient&quot;
)

func main() {
	client, err := ethclient.Dial(&quot;wss://sepolia.infura.io/ws/v3/YOUR_PROJECT_ID&quot;)
	if err != nil {
		log.Fatalf(&quot;❌ 连接节点失败: %v&quot;, err)
	}

	// ERC20 合约地址
	tokenAddress := common.HexToAddress(&quot;0xYourTokenAddress&quot;)

	query := ethereum.FilterQuery{
		Addresses: []common.Address{tokenAddress},
	}

	logsCh := make(chan types.Log)
	sub, err := client.SubscribeFilterLogs(context.Background(), query, logsCh)
	if err != nil {
		log.Fatalf(&quot;❌ 订阅失败: %v&quot;, err)
	}

	tokenAbi, _ := abi.JSON(strings.NewReader(`[{&quot;anonymous&quot;:false,&quot;inputs&quot;:[
		{&quot;indexed&quot;:true,&quot;name&quot;:&quot;from&quot;,&quot;type&quot;:&quot;address&quot;},
		{&quot;indexed&quot;:true,&quot;name&quot;:&quot;to&quot;,&quot;type&quot;:&quot;address&quot;},
		{&quot;indexed&quot;:false,&quot;name&quot;:&quot;value&quot;,&quot;type&quot;:&quot;uint256&quot;}
	],&quot;name&quot;:&quot;Transfer&quot;,&quot;type&quot;:&quot;event&quot;}]`))

	fmt.Println(&quot;🎧 已开始监听 ERC20 Transfer 事件...&quot;)

	for {
		select {
		case err := &amp;lt;-sub.Err():
			log.Println(&quot;⚠️ 错误:&quot;, err)
		case vLog := &amp;lt;-logsCh:
			var transfer struct {
				From  common.Address
				To    common.Address
				Value *big.Int
			}

			tokenAbi.UnpackIntoInterface(&amp;amp;transfer, &quot;Transfer&quot;, vLog.Data)
			transfer.From = common.HexToAddress(vLog.Topics[1].Hex())
			transfer.To = common.HexToAddress(vLog.Topics[2].Hex())

			fmt.Printf(&quot;\n📦 区块: %d\nFrom: %s\nTo: %s\nValue: %s\n&quot;,
				vLog.BlockNumber, transfer.From.Hex(), transfer.To.Hex(), transfer.Value.String())
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输出示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;🎧 已开始监听 ERC20 Transfer 事件...

📦 区块: 5439812
From: 0x23dE...B45C
To:   0x91a0...CCfA
Value: 1000000000000000000
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;五、gRPC 模式：更底层的流式监听&lt;/h2&gt;
&lt;p&gt;以太坊的 gRPC 接口定义在 go-ethereum 的 proto 文件中：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;interfaces/grpc.proto&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;通过 &lt;code&gt;protoc&lt;/code&gt; 生成的接口可直接被 Go 调用。&lt;/p&gt;
&lt;p&gt;你可以使用官方客户端包 &lt;code&gt;github.com/ethereum/go-ethereum/rpc&lt;/code&gt; 以 &lt;code&gt;DialContext&lt;/code&gt; 的方式连接 gRPC 节点。&lt;/p&gt;
&lt;h3&gt;1. 节点启动参数&lt;/h3&gt;
&lt;p&gt;如果你运行的是本地 geth 节点，可以这样启动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;geth --grpc --grpc.addr 0.0.0.0 --grpc.port 8547
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;2. 连接 gRPC 通道&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;import (
	&quot;context&quot;
	&quot;log&quot;

	&quot;github.com/ethereum/go-ethereum/rpc&quot;
)

func main() {
	client, err := rpc.DialContext(context.Background(), &quot;grpc://127.0.0.1:8547&quot;)
	if err != nil {
		log.Fatalf(&quot;❌ 无法连接 gRPC 节点: %v&quot;, err)
	}
	defer client.Close()

	log.Println(&quot;✅ 已连接到 gRPC 节点&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;3. 通过 gRPC 订阅新区块&lt;/h3&gt;
&lt;p&gt;在 gRPC 模式下，所有的订阅事件都是通过流（stream）进行的。&lt;/p&gt;
&lt;p&gt;以下示例展示如何监听新区块头（&lt;code&gt;NewHeads&lt;/code&gt;）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import (
	&quot;context&quot;
	&quot;fmt&quot;
	&quot;log&quot;

	&quot;github.com/ethereum/go-ethereum/core/types&quot;
	&quot;github.com/ethereum/go-ethereum/rpc&quot;
)

func main() {
	client, err := rpc.DialContext(context.Background(), &quot;grpc://127.0.0.1:8547&quot;)
	if err != nil {
		log.Fatalf(&quot;❌ gRPC 连接失败: %v&quot;, err)
	}
	defer client.Close()

	headers := make(chan *types.Header)
	sub, err := client.EthSubscribe(context.Background(), headers, &quot;newHeads&quot;)
	if err != nil {
		log.Fatalf(&quot;❌ 订阅失败: %v&quot;, err)
	}

	fmt.Println(&quot;🎧 正在通过 gRPC 监听新区块...&quot;)

	for {
		select {
		case err := &amp;lt;-sub.Err():
			log.Println(&quot;⚠️ 订阅错误:&quot;, err)
		case h := &amp;lt;-headers:
			fmt.Printf(&quot;⛓️ 新区块 #%v | 哈希: %s\n&quot;, h.Number, h.Hash())
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输出示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;🎧 正在通过 gRPC 监听新区块...
⛓️ 新区块 #8923121 | 哈希: 0x42b2f...
⛓️ 新区块 #8923122 | 哈希: 0x5cc99...
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;4. gRPC 模式监听日志事件&lt;/h3&gt;
&lt;p&gt;与 WSS 类似，只是连接方式不同：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sub, err := client.EthSubscribe(context.Background(), logsCh, &quot;logs&quot;, map[string]interface{}{
	&quot;address&quot;: []string{&quot;0xYourContract&quot;},
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一旦事件被触发，客户端会收到结构化的 &lt;code&gt;types.Log&lt;/code&gt; 对象。&lt;/p&gt;
&lt;h2&gt;六、底层机制：事件是如何被推送的？&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;节点执行交易 → 生成日志（Log）和收据（Receipt）；&lt;/li&gt;
&lt;li&gt;新区块被打包并广播；&lt;/li&gt;
&lt;li&gt;订阅服务检测到匹配事件（通过 FilterQuery）；&lt;/li&gt;
&lt;li&gt;节点将事件推送给客户端通道；&lt;/li&gt;
&lt;li&gt;客户端在通道中读取事件流，实时处理。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;八、小结与思考&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;关键点&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ethclient.SubscribeNewHead&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;监听新区块&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ethclient.SubscribeFilterLogs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;监听合约事件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rpc.DialContext(&quot;grpc://...&quot;)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;通过 gRPC 通道连接节点&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;EthSubscribe()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;通用订阅接口&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gRPC 模式&lt;/td&gt;
&lt;td&gt;更高效的事件流通信方式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WebSocket 模式&lt;/td&gt;
&lt;td&gt;最兼容的通用监听方式&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded><author>Derick</author></item><item><title>读懂区块 —— 以太坊的时间机器</title><link>https://blog.ithuo.net/posts/blockchain-tutorial-evm-3/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/blockchain-tutorial-evm-3/</guid><pubDate>Fri, 06 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;“每一个区块，都是一次全网共识的快照。&lt;/p&gt;
&lt;p&gt;它不仅记录了交易，更记录了时间的流逝。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;一、开场：区块，不只是数据&lt;/h2&gt;
&lt;p&gt;在上一讲中，我们成功连上了以太坊节点，并读取了&lt;strong&gt;最新区块号&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;那时，我们看到的只是一个数字——&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;最新的区块号是: 5689012
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但如果说，这个数字代表了&lt;strong&gt;以太坊心脏跳动的节奏&lt;/strong&gt;，你是否会想更进一步？&lt;/p&gt;
&lt;p&gt;——这些区块，到底“长什么样”？&lt;/p&gt;
&lt;p&gt;——它们存着什么？&lt;/p&gt;
&lt;p&gt;——交易又是如何被打包进去的？&lt;/p&gt;
&lt;p&gt;在这一讲，我们就来一起“拆开”一个区块，看看里面的世界。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;二、区块的本质：世界状态的“快照”&lt;/h2&gt;
&lt;p&gt;如果你来自传统后端背景，可以这样理解：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在数据库中，&lt;strong&gt;一次事务提交&lt;/strong&gt; 会改变数据状态；&lt;/li&gt;
&lt;li&gt;在区块链中，&lt;strong&gt;一次区块确认&lt;/strong&gt; 会改变全网状态。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每一个区块（&lt;code&gt;Block&lt;/code&gt;）都像一张“快照”，&lt;/p&gt;
&lt;p&gt;记录了自上一个区块以来，发生的所有状态变化。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;概念&lt;/th&gt;
&lt;th&gt;类比&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;区块号 (&lt;code&gt;Block Number&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;数据版本号&lt;/td&gt;
&lt;td&gt;记录世界状态的顺序&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;区块哈希 (&lt;code&gt;Block Hash&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;快照 ID&lt;/td&gt;
&lt;td&gt;唯一标识这个区块内容&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;父区块哈希 (&lt;code&gt;Parent Hash&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;上一个版本指针&lt;/td&gt;
&lt;td&gt;像 Git 的 &lt;code&gt;parent commit&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;时间戳 (&lt;code&gt;Timestamp&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;提交时间&lt;/td&gt;
&lt;td&gt;区块打包的时间&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;交易列表 (&lt;code&gt;Transactions&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;操作日志&lt;/td&gt;
&lt;td&gt;区块内包含的所有操作&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;以太坊区块链，就是由这些“快照”首尾相连形成的时间长河。&lt;/p&gt;
&lt;p&gt;你可以随时读取过去任何一个区块的状态，就像翻阅时间机器中的档案。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;三、Go-Ethereum 实战：读取一个完整区块&lt;/h2&gt;
&lt;p&gt;接下来，我们动手验证这一切。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;目标：&lt;/p&gt;
&lt;p&gt;使用 Go 语言获取最新区块的详细信息，&lt;/p&gt;
&lt;p&gt;并打印其中的核心字段。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;1. 新建文件 &lt;code&gt;block_inspect.go&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;context&quot;
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;math/big&quot;

	&quot;github.com/ethereum/go-ethereum/ethclient&quot;
)

func main() {
	// 1. 连接到节点
	client, err := ethclient.Dial(&quot;https://sepolia.infura.io/v3/&amp;lt;YOUR_PROJECT_ID&amp;gt;&quot;)
	if err != nil {
		log.Fatalf(&quot;连接节点失败: %v&quot;, err)
	}

	// 2. 获取最新区块头，拿到区块号
	header, err := client.HeaderByNumber(context.Background(), nil)
	if err != nil {
		log.Fatalf(&quot;无法获取区块头: %v&quot;, err)
	}
	blockNumber := header.Number

	fmt.Printf(&quot;🔹 当前最新区块号: %v\n&quot;, blockNumber)

	// 3. 获取完整区块对象
	block, err := client.BlockByNumber(context.Background(), blockNumber)
	if err != nil {
		log.Fatalf(&quot;无法获取区块信息: %v&quot;, err)
	}

	// 4. 打印关键字段
	fmt.Println(&quot;———————— 区块信息 ————————&quot;)
	fmt.Printf(&quot;区块号: %v\n&quot;, block.Number())
	fmt.Printf(&quot;区块哈希: %v\n&quot;, block.Hash().Hex())
	fmt.Printf(&quot;父区块哈希: %v\n&quot;, block.ParentHash().Hex())
	fmt.Printf(&quot;时间戳: %v\n&quot;, block.Time())
	fmt.Printf(&quot;交易数量: %d\n&quot;, len(block.Transactions()))

	// 5. 读取区块内的第一笔交易（若存在）
	if len(block.Transactions()) &amp;gt; 0 {
		tx := block.Transactions()[0]
		fmt.Println(&quot;———————— 第一笔交易 ————————&quot;)
		fmt.Printf(&quot;交易哈希: %v\n&quot;, tx.Hash().Hex())
		fmt.Printf(&quot;发起地址: %v\n&quot;, tx.From()) // 注意：tx.From() 需要额外签名信息，此处略
		fmt.Printf(&quot;接收地址: %v\n&quot;, tx.To())
		fmt.Printf(&quot;Gas 消耗上限: %v\n&quot;, tx.Gas())
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行它：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go run block_inspect.go
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;你会看到类似输出：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;🔹 当前最新区块号: 5689012
———————— 区块信息 ————————
区块号: 5689012
区块哈希: 0x7f3a1d...
父区块哈希: 0x9b7f20...
时间戳: 1731098890
交易数量: 142
———————— 第一笔交易 ————————
交易哈希: 0xa1b9f...
接收地址: 0x32F0...D5a
Gas 消耗上限: 21000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;恭喜！你已经成功“读懂”了一个区块的骨架。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;四、交易：区块的灵魂&lt;/h2&gt;
&lt;p&gt;区块是容器，交易是灵魂。&lt;/p&gt;
&lt;p&gt;在以太坊中，所有状态变化（账户余额、合约执行、事件日志）都来源于交易。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;没有交易，就没有区块。&lt;/p&gt;
&lt;p&gt;没有区块，就没有状态。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;一笔交易包含什么？&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;字段&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nonce&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;发送者账户的交易计数器，防止重放&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;to&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;接收方地址（若为空，则是部署合约）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;value&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;转账的 ETH 数量&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gas&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;允许消耗的最大 Gas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gasPrice&lt;/code&gt; / &lt;code&gt;maxFeePerGas&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;每单位 Gas 的费用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;合约调用参数或部署代码&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;v, r, s&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;签名字段，验证交易的合法性&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;当节点验证一笔交易时，它实际上在&lt;strong&gt;EVM 沙箱中执行了这段代码&lt;/strong&gt;，&lt;/p&gt;
&lt;p&gt;然后将执行结果（包括状态变化、事件日志）记录入区块。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;五、区块链中的时间与不可逆性&lt;/h2&gt;
&lt;p&gt;每个区块都有一个时间戳 &lt;code&gt;timestamp&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;它并不是毫秒级精度，而是区块被“打包”进链时的粗略时间。&lt;/p&gt;
&lt;p&gt;区块之间间隔大约为 12 秒（PoS 共识下），&lt;/p&gt;
&lt;p&gt;这意味着以太坊的“时间”是由共识推动的，而非系统时钟。&lt;/p&gt;
&lt;p&gt;区块链世界的时间有一个重要特征：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;过去的状态永远不会被修改，只能被追加。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这就是所谓的&lt;strong&gt;不可篡改性（Immutability）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;而这，也正是它区别于一切传统数据库的根本。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;六、思考与扩展&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;能否通过代码获取指定区块号的区块？
&lt;blockquote&gt;
&lt;p&gt;提示：client.BlockByNumber(ctx, big.NewInt(1234567))&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;能否将区块数据以 JSON 格式输出？
&lt;blockquote&gt;
&lt;p&gt;试着用 json.MarshalIndent(block, &quot;&quot;, &quot;  &quot;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;区块中有 100 多笔交易，你能否循环遍历并打印它们的哈希？
&lt;blockquote&gt;
&lt;p&gt;下一讲，我们就要这么做。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;七、过渡：从区块到交易日志&lt;/h2&gt;
&lt;p&gt;我们已经看到了区块和交易的结构。&lt;/p&gt;
&lt;p&gt;但在智能合约的世界中，真正有价值的数据往往隐藏在**事件日志（Logs）**中。&lt;/p&gt;
&lt;p&gt;它们是应用层的“信号”，&lt;/p&gt;
&lt;p&gt;代表某个合约函数被执行、某笔业务逻辑已触发。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;八、总结&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;我们学到了什么&lt;/th&gt;
&lt;th&gt;关键点&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;区块是以太坊的时间片段&lt;/td&gt;
&lt;td&gt;每个区块都是全网状态的快照&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;交易是状态变化的源头&lt;/td&gt;
&lt;td&gt;每笔交易都会改变链上状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;区块哈希形成了链式结构&lt;/td&gt;
&lt;td&gt;确保数据不可篡改&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Go 语言可轻松读取区块内容&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BlockByNumber&lt;/code&gt; 是关键方法&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded><author>Derick</author></item><item><title>连接区块链 —— 你的第一个 Go-EVM 程序</title><link>https://blog.ithuo.net/posts/blockchain-tutorial-evm-2/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/blockchain-tutorial-evm-2/</guid><pubDate>Fri, 06 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;“写下第一个能和以太坊说话的程序，&lt;/p&gt;
&lt;p&gt;就像拨通一台星球级计算机的电话。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在上一讲，我们认识了以太坊的世界观：&lt;/p&gt;
&lt;p&gt;它是一台由全世界共同维护的计算机，每个节点都是它的一部分。&lt;/p&gt;
&lt;p&gt;这一次，我们不再只做旁观者。&lt;/p&gt;
&lt;p&gt;我们将真正&lt;strong&gt;与它建立通信&lt;/strong&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;一、目标：拨通以太坊的电话线&lt;/h2&gt;
&lt;p&gt;本章的目标非常具体：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;使用 Go 语言，通过 JSON-RPC 接口连接以太坊测试网（Sepolia），&lt;/p&gt;
&lt;p&gt;并打印当前最新区块号。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;听起来很简单，但这一步的意义重大。&lt;/p&gt;
&lt;p&gt;它代表着你第一次通过代码，&lt;/p&gt;
&lt;p&gt;跨越成千上万台节点，与区块链直接通信。&lt;/p&gt;
&lt;p&gt;这就像在浩瀚的星海中，&lt;/p&gt;
&lt;p&gt;你发出了属于自己的第一个信号。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;二、准备环境：一切从「干净的终端」开始&lt;/h2&gt;
&lt;p&gt;在开始前，请确保你具备以下条件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ 安装 Go 1.21 或以上版本&lt;/li&gt;
&lt;li&gt;✅ 拥有一个可用的节点服务（推荐使用 Infura 或 Alchemy）&lt;/li&gt;
&lt;li&gt;✅ 了解如何运行一个最基本的 Go 程序&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果你还没有节点服务，可以这样准备：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;访问 &lt;a href=&quot;https://infura.io/&quot;&gt;https://infura.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;注册账号 → 创建新项目&lt;/li&gt;
&lt;li&gt;选择网络：&lt;strong&gt;Ethereum → Sepolia Testnet&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;获取 RPC URL，例如：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;https://sepolia.infura.io/v3/&amp;lt;YOUR_PROJECT_ID&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;💡 提示：&lt;/p&gt;
&lt;p&gt;Sepolia 是以太坊官方测试网，你可以在上面做任何实验，而无需使用真实代币。&lt;/p&gt;
&lt;p&gt;这使它成为区块链开发的“沙盒宇宙”。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;三、Go-Ethereum：连接 EVM 世界的“钥匙”&lt;/h2&gt;
&lt;p&gt;以太坊官方提供了一个功能完整的 Go 实现，叫 &lt;strong&gt;go-ethereum&lt;/strong&gt;（简称 &lt;code&gt;geth&lt;/code&gt;）。&lt;/p&gt;
&lt;p&gt;而它的子包 &lt;code&gt;ethclient&lt;/code&gt;，正是我们与链交互的核心库。&lt;/p&gt;
&lt;p&gt;在终端中执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go mod init hello-ethereum
go get github.com/ethereum/go-ethereum
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这两步完成后，你的项目便具备了连接 EVM 的全部能力。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;四、代码：最小可行的以太坊客户端&lt;/h2&gt;
&lt;p&gt;创建一个新文件 &lt;code&gt;main.go&lt;/code&gt;，输入以下代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
    &quot;context&quot;
    &quot;fmt&quot;
    &quot;log&quot;

    &quot;github.com/ethereum/go-ethereum/ethclient&quot;
)

func main() {
    // 1. 连接节点
    client, err := ethclient.Dial(&quot;https://sepolia.infura.io/v3/&amp;lt;YOUR_PROJECT_ID&amp;gt;&quot;)
    if err != nil {
        log.Fatalf(&quot;连接节点失败: %v&quot;, err)
    }
    defer client.Close()

    // 2. 获取当前区块号
    blockNumber, err := client.BlockNumber(context.Background())
    if err != nil {
        log.Fatalf(&quot;获取区块号失败: %v&quot;, err)
    }

    fmt.Printf(&quot;✅ 成功连接到以太坊测试网\n当前最新区块号: %d\n&quot;, blockNumber)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行它：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go run main.go
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果一切顺利，你将看到类似输出：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;✅ 成功连接到以太坊测试网
当前最新区块号: 5689012
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那一刻，你的代码已经在和全球的以太坊节点实时对话。&lt;/p&gt;
&lt;p&gt;你从零，完成了与区块链的第一次握手。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;五、代码拆解：每一行都在拨动“世界计算机”的齿轮&lt;/h2&gt;
&lt;p&gt;让我们仔细拆解刚才的几行代码。&lt;/p&gt;
&lt;h3&gt;1. &lt;code&gt;ethclient.Dial()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;这是你连接区块链节点的“拨号”操作。&lt;/p&gt;
&lt;p&gt;它底层通过 &lt;strong&gt;JSON-RPC over HTTP/WebSocket&lt;/strong&gt; 协议建立通信通道。&lt;/p&gt;
&lt;p&gt;在传统 Web 开发中，我们习惯使用 &lt;code&gt;http.Client&lt;/code&gt; 请求 API。&lt;/p&gt;
&lt;p&gt;而这里的 &lt;code&gt;ethclient&lt;/code&gt; 是对区块链节点 API 的专用封装。&lt;/p&gt;
&lt;p&gt;它知道该如何向节点发送 &lt;code&gt;&quot;eth_blockNumber&quot;&lt;/code&gt; 方法请求，并解析响应。&lt;/p&gt;
&lt;h3&gt;2. &lt;code&gt;client.BlockNumber()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;这是一次标准的 RPC 调用，&lt;/p&gt;
&lt;p&gt;对应底层的 JSON 请求：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;jsonrpc&quot;: &quot;2.0&quot;,
  &quot;method&quot;: &quot;eth_blockNumber&quot;,
  &quot;params&quot;: [],
  &quot;id&quot;: 1
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;节点收到请求后，会返回当前链的最新区块号（以十六进制表示）。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;go-ethereum&lt;/code&gt; 帮我们完成了解码与转换。&lt;/p&gt;
&lt;h3&gt;3. &lt;code&gt;context.Background()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;以太坊交互往往需要网络 I/O。&lt;/p&gt;
&lt;p&gt;Go 的 &lt;code&gt;context&lt;/code&gt; 是控制超时、取消请求的重要机制。&lt;/p&gt;
&lt;p&gt;在更复杂的程序中，我们会用它来防止长时间阻塞，&lt;/p&gt;
&lt;p&gt;比如监听区块、轮询事件等。&lt;/p&gt;
&lt;hr /&gt;
</content:encoded><author>Derick</author></item><item><title>Hello Ethereum！</title><link>https://blog.ithuo.net/posts/blockchain-tutorial-evm-1/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/blockchain-tutorial-evm-1/</guid><pubDate>Tue, 03 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;你好，以太坊！—— 从后端视角看“世界计算机”&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;🌍 本章目标：建立对以太坊的整体认知。&lt;/p&gt;
&lt;p&gt;你将不再把区块链当作一个“黑盒”，而是能用后端工程师的视角，看懂它的结构、语言与运行逻辑。&lt;/p&gt;
&lt;p&gt;本章不求你写出多少代码，而是希望你看完后能说出一句——&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;“原来以太坊，真的就像一台全球共享的计算机。”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;一、从“服务器”到“世界计算机”&lt;/h2&gt;
&lt;p&gt;还记得我们最熟悉的 Web 架构吗？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;客户端 → 服务器 → 数据库&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们写接口、连数据库、部署后端，一切都在一家公司自己的服务器上运行。&lt;/p&gt;
&lt;p&gt;这就是 &lt;strong&gt;中心化系统（Centralized System）&lt;/strong&gt; —— 所有数据与逻辑都掌握在单一机构手中。&lt;/p&gt;
&lt;p&gt;现在想象一下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;如果这个“服务器”不属于任何一家公司，&lt;/p&gt;
&lt;p&gt;而是全球上万台机器同时维护、共同执行逻辑，&lt;/p&gt;
&lt;p&gt;每个节点都保存完整的数据副本，&lt;/p&gt;
&lt;p&gt;那么它会变成什么？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这就是以太坊（&lt;strong&gt;Ethereum&lt;/strong&gt;）。&lt;/p&gt;
&lt;p&gt;以太坊是一台由全世界共同运行的计算机。&lt;/p&gt;
&lt;p&gt;它不是某个云服务，而是一个&lt;strong&gt;人人都能参与的、不可篡改的、开放的计算平台&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;它运行的代码叫 &lt;strong&gt;智能合约（Smart Contract）&lt;/strong&gt;，执行环境叫 &lt;strong&gt;EVM（以太坊虚拟机）&lt;/strong&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;二、智能合约：去中心化世界的后端代码&lt;/h2&gt;
&lt;p&gt;在中心化应用中，后端服务通常由我们自己维护。&lt;/p&gt;
&lt;p&gt;我们可以修改逻辑、更新版本、甚至删除用户数据。&lt;/p&gt;
&lt;p&gt;但在以太坊上，逻辑以“智能合约”的形式部署，一旦发布就无法随意更改。&lt;/p&gt;
&lt;p&gt;它是自动执行的程序，由整个网络共同维护。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;概念&lt;/th&gt;
&lt;th&gt;Web2 对应物&lt;/th&gt;
&lt;th&gt;Web3（以太坊）对应物&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;应用逻辑&lt;/td&gt;
&lt;td&gt;后端服务&lt;/td&gt;
&lt;td&gt;智能合约&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;执行环境&lt;/td&gt;
&lt;td&gt;服务器&lt;/td&gt;
&lt;td&gt;EVM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;数据库&lt;/td&gt;
&lt;td&gt;MySQL/PostgreSQL&lt;/td&gt;
&lt;td&gt;区块链账本&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;部署&lt;/td&gt;
&lt;td&gt;CI/CD 部署服务&lt;/td&gt;
&lt;td&gt;发布到区块链&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;用户请求&lt;/td&gt;
&lt;td&gt;HTTP 调用&lt;/td&gt;
&lt;td&gt;交易 (Transaction)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;一句话总结：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;智能合约 = 运行在区块链上的后端服务。&lt;/p&gt;
&lt;p&gt;一旦部署，它就“永远在线”，无法被某个人关闭。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;三、EVM：让全世界计算出同一个结果&lt;/h2&gt;
&lt;p&gt;EVM（Ethereum Virtual Machine）是以太坊的核心。&lt;/p&gt;
&lt;p&gt;它确保每个节点在执行合约时，都能得到完全相同的结果。&lt;/p&gt;
&lt;p&gt;不管你在台北、纽约还是巴黎，只要在同一区块高度执行相同的合约调用，&lt;/p&gt;
&lt;p&gt;每个节点的输出都必须一致。否则，网络就会分裂。&lt;/p&gt;
&lt;p&gt;这就是“去中心化计算”的奇妙之处：&lt;/p&gt;
&lt;p&gt;每一次执行，都是&lt;strong&gt;所有节点的共识计算&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;从开发者视角看，EVM 是一个“安全沙箱”：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;它限制智能合约的运行时间（用 &lt;strong&gt;Gas&lt;/strong&gt; 控制成本）&lt;/li&gt;
&lt;li&gt;它规定数据访问方式（合约存储、状态树）&lt;/li&gt;
&lt;li&gt;它屏蔽了底层系统差异，保证确定性执行&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果你来自后端开发背景，可以把它理解成一个：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“运行在全球分布式数据库上的虚拟机”。&lt;/p&gt;
&lt;p&gt;它既能执行代码，又能保证状态一致。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;四、节点与 JSON-RPC：你与区块链的对话通道&lt;/h2&gt;
&lt;p&gt;既然以太坊是“世界计算机”，那我们该如何和它对话？&lt;/p&gt;
&lt;p&gt;答案是 —— 通过 &lt;strong&gt;节点 (Node)&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;节点是以太坊网络的“接入点”，存储了完整或部分链上数据，并提供通信接口。&lt;/p&gt;
&lt;p&gt;每个节点都能处理请求、广播交易、同步最新区块。&lt;/p&gt;
&lt;p&gt;我们与节点通信的协议叫 &lt;strong&gt;JSON-RPC&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;如果你写过 RESTful API 或 gRPC，这个概念会非常亲切。&lt;/p&gt;
&lt;p&gt;下面是一个典型请求示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;jsonrpc&quot;: &quot;2.0&quot;,
  &quot;method&quot;: &quot;eth_getBlockByNumber&quot;,
  &quot;params&quot;: [&quot;latest&quot;, false],
  &quot;id&quot;: 1
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它就像是在问节点：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“请告诉我以太坊当前最新区块的内容。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;节点返回的结果是标准化的 JSON，对后端开发者非常友好。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;五、节点从哪里来？——“自己搭”还是“租一个”&lt;/h2&gt;
&lt;p&gt;在开发阶段，我们一般不会自己从零搭建节点。&lt;/p&gt;
&lt;p&gt;因为全节点同步需要巨量的磁盘和网络资源。&lt;/p&gt;
&lt;p&gt;所以更常见的做法是使用 &lt;strong&gt;节点服务商（Node as a Service）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;可以把它理解成 “区块链版的 AWS RDS”。&lt;/p&gt;
&lt;p&gt;你不需要自己搭建数据库，只要获取一个 API Endpoint，就能直接读写链上数据。&lt;/p&gt;
&lt;h3&gt;主流节点服务商简评：&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;服务商&lt;/th&gt;
&lt;th&gt;特点&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Infura&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;以太坊生态最老牌节点服务，由 ConsenSys 维护，稳定可靠。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Alchemy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;提供增强型 API 与强大开发工具，深受开发者欢迎。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;QuickNode&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;以速度与多区域性能著称。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ankr / Chainstack&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;性价比高，API 丰富，适合多链开发。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;🔑 实践准备：&lt;/p&gt;
&lt;p&gt;你可以去 &lt;a href=&quot;https://infura.io/&quot;&gt;Infura&lt;/a&gt; 或 &lt;a href=&quot;https://alchemy.com/&quot;&gt;Alchemy&lt;/a&gt; 注册免费账号，&lt;/p&gt;
&lt;p&gt;创建一个项目并获取测试网（例如 Sepolia）的 RPC URL。&lt;/p&gt;
&lt;p&gt;这是你未来章节中“连接以太坊”的通行证。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;六、区块、交易与收据：区块链的数据世界&lt;/h2&gt;
&lt;p&gt;区块链的数据结构其实并不神秘。&lt;/p&gt;
&lt;p&gt;它只是在传统数据库基础上，&lt;strong&gt;加上了时间顺序和不可篡改性&lt;/strong&gt;。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;概念&lt;/th&gt;
&lt;th&gt;类比&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;区块 (Block)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;一次批量提交&lt;/td&gt;
&lt;td&gt;打包多笔交易的容器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;区块哈希&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;唯一指纹&lt;/td&gt;
&lt;td&gt;通过哈希算法生成，用来防止篡改&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;交易 (Transaction)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;用户请求&lt;/td&gt;
&lt;td&gt;用户发起的操作，如转账或调用合约&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;交易哈希&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;请求 ID&lt;/td&gt;
&lt;td&gt;用于追踪交易状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;收据 (Receipt)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;执行结果&lt;/td&gt;
&lt;td&gt;记录交易是否成功、消耗多少 Gas、触发哪些事件&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;可以这么想：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;区块就像数据库的 commit log，&lt;/p&gt;
&lt;p&gt;交易是一次请求，&lt;/p&gt;
&lt;p&gt;收据是请求执行后的返回值。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;当你理解了“区块是数据库提交记录”的这个比喻，你就能自然地看懂链上数据。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;七、小小预告：你的第一个 Go-EVM 程序&lt;/h2&gt;
&lt;p&gt;为了让概念更“落地”，我们在下一讲中将真正动手，&lt;/p&gt;
&lt;p&gt;使用 Go 语言与 &lt;code&gt;go-ethereum&lt;/code&gt; 库连接到 Sepolia 测试网，&lt;/p&gt;
&lt;p&gt;并获取当前最新区块号。&lt;/p&gt;
&lt;p&gt;你将看到这样一个输出：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;✅ 成功连接到 Sepolia 测试网！
最新的区块号是: 5432100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它意味着你真正与“世界计算机”建立了联系。&lt;/p&gt;
&lt;p&gt;从那一刻起，你就不是区块链的旁观者，而是它的参与者。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;八、总结（Key Takeaways）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;以太坊是一台全球分布式的“世界计算机”。&lt;/li&gt;
&lt;li&gt;智能合约是这台计算机的“后端程序”。&lt;/li&gt;
&lt;li&gt;EVM 确保所有节点执行同样代码得到同样结果。&lt;/li&gt;
&lt;li&gt;节点是你与区块链的“API 网关”，通过 JSON-RPC 通信。&lt;/li&gt;
&lt;li&gt;区块、交易、收据是链上数据的三大基本结构。&lt;/li&gt;
&lt;li&gt;下一讲，我们将正式用 Go 语言“握手”以太坊测试网。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;后续章节规划（系列路线图）&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;章节&lt;/th&gt;
&lt;th&gt;核心主题&lt;/th&gt;
&lt;th&gt;学习目标&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;第 1 讲&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;你好，以太坊！&lt;/td&gt;
&lt;td&gt;建立心智模型，理解 EVM 世界观&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;第 2 讲&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;连接区块链&lt;/td&gt;
&lt;td&gt;编写第一个 Go 程序，读取区块&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;第 3 讲&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;探索交易&lt;/td&gt;
&lt;td&gt;查询交易详情与执行结果&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;第 4 讲&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;事件与日志&lt;/td&gt;
&lt;td&gt;解析智能合约事件（Logs）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;第 5 讲&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;扫链与索引&lt;/td&gt;
&lt;td&gt;构建自己的数据索引器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;第 6 讲&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;签名与发送交易&lt;/td&gt;
&lt;td&gt;发送真实交易、管理 nonce&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;第 7 讲&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;实战篇：监听代币转账&lt;/td&gt;
&lt;td&gt;开发一个实时链上监控工具&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;尾声&lt;/h2&gt;
&lt;p&gt;到这里，你已经完成了 Web3 世界的“入境登记”。&lt;/p&gt;
&lt;p&gt;接下来，我们将用 Go 语言打开第一个“窗口”，&lt;/p&gt;
&lt;p&gt;去看看这台世界计算机的心跳 —— 区块。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>在本地运行Substrate开发节点</title><link>https://blog.ithuo.net/posts/how-to-run-a-local-substrate-node-tutorial/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/how-to-run-a-local-substrate-node-tutorial/</guid><pubDate>Sat, 30 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Substrate是一个强大而灵活的区块链开发框架，由Parity Technologies团队开发，旨在简化和加速区块链的创建过程。它与Polkadot有着密切的关系，但同时也是一个独立的工具。让我们深入了解Substrate及其与Polkadot的联系。&lt;/p&gt;
&lt;h2&gt;什么是Substrate?&lt;/h2&gt;
&lt;p&gt;Substrate是一个用于构建自定义区块链的开源框架。它具有以下特点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;可扩展性&lt;/strong&gt;：Substrate允许开发者根据特定需求创建定制化的区块链。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模块化&lt;/strong&gt;：框架采用高度模块化的设计，开发者可以轻松组合和定制各种组件。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;灵活性&lt;/strong&gt;：支持多种共识机制、加密算法和治理模型。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能优化&lt;/strong&gt;：Substrate经过优化，可以处理高吞吐量和复杂的区块链操作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跨链兼容性&lt;/strong&gt;：原生支持与其他基于Substrate的链进行互操作。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Substrate与Polkadot的关系&lt;/h2&gt;
&lt;p&gt;Substrate和Polkadot之间存在密切但可分离的关系：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;技术基础&lt;/strong&gt;：Polkadot本身就是使用Substrate构建的，这证明了Substrate的强大功能和灵活性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;平行链开发&lt;/strong&gt;：Substrate是开发Polkadot生态系统中平行链的首选工具。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;互操作性&lt;/strong&gt;：基于Substrate构建的链可以轻松地与Polkadot网络集成，成为一条平行链或平行线程。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;独立性&lt;/strong&gt;：尽管与Polkadot紧密相连，但Substrate构建的链也可以作为独立的区块链运行，不必连接到Polkadot网络。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生态系统共享&lt;/strong&gt;：Substrate项目可以利用Polkadot的安全性、跨链通信能力和不断增长的生态系统。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Substrate的优势&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;快速开发&lt;/strong&gt;：Substrate提供了许多预建模块，大大缩短了区块链开发时间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;定制化&lt;/strong&gt;：开发者可以根据特定用例优化其区块链，而不受现有平台的限制。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;升级性&lt;/strong&gt;：Substrate支持无分叉升级，允许区块链随时间演进而不中断。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;互操作性&lt;/strong&gt;：原生支持跨链通信，特别是在Polkadot生态系统中。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;社区支持&lt;/strong&gt;：作为开源项目，Substrate拥有活跃的开发者社区和丰富的资源。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;总之，Substrate是一个强大的区块链开发框架，为开发者提供了构建创新区块链解决方案所需的工具。虽然它与Polkadot有着密切的联系，但Substrate的应用范围远不止于此，为区块链技术的未来发展开辟了广阔的可能性。&lt;/p&gt;
&lt;p&gt;:::tip
下面将一步步搭建本地substrate节点并进行转账，查看交易等操作，请提前根据&lt;a href=&quot;https://substrate-docs.pages.dev/en/install/macos/?mode=light&quot;&gt;文档&lt;/a&gt;配置substrate运行环境
:::&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;papermoonio/polkadot-sdk-solo-template-dev-courses&quot;}&lt;/p&gt;
&lt;h3&gt;下载仓库并编译&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;git clone  https://github.com/papermoonio/polkadot-sdk-solo-template-dev-courses 
cd polkadot-sdk-solo-template-dev-courses
cargo build --release
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;查看节点使用帮助说明&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;root@localhost:~/code/substrate/polkadot-sdk-solo-template-dev-courses# ./target/release/solochain-template-node -h
A solochain node template built with Substrate, part of Polkadot Sdk.

Usage: solochain-template-node [OPTIONS]
       solochain-template-node &amp;lt;COMMAND&amp;gt;

Commands:
  key            Key management cli utilities
  build-spec     Build a chain specification
  check-block    Validate blocks
  export-blocks  Export blocks
  export-state   Export the state of a given block into a chain spec
  import-blocks  Import blocks
  purge-chain    Remove the whole chain
  revert         Revert the chain to a previous state
  benchmark      Sub-commands concerned with benchmarking
  try-runtime    Try-runtime has migrated to a standalone CLI (&amp;lt;https://github.com/paritytech/try-runtime-cli&amp;gt;). The subcommand exists as a stub and deprecation notice. It will be removed entirely some time after January 2024
  chain-info     Db meta columns information
  help           Print this message or the help of the given subcommand(s)

Options:
      --validator                                                                                Enable validator mode
      --no-grandpa                                                                               Disable GRANDPA
      --rpc-external                                                                             Listen to all RPC interfaces (default: local)
      --unsafe-rpc-external                                                                      Listen to all RPC interfaces
      --rpc-methods &amp;lt;METHOD SET&amp;gt;                                                                 RPC methods to expose. [default: auto] [possible values: auto, safe, unsafe]
      --rpc-rate-limit &amp;lt;RPC_RATE_LIMIT&amp;gt;                                                          RPC rate limiting (calls/minute) for each connection
      --rpc-max-request-size &amp;lt;RPC_MAX_REQUEST_SIZE&amp;gt;                                              Set the maximum RPC request payload size for both HTTP and WS in megabytes [default: 15]
      --rpc-max-response-size &amp;lt;RPC_MAX_RESPONSE_SIZE&amp;gt;                                            Set the maximum RPC response payload size for both HTTP and WS in megabytes [default: 15]
      --rpc-max-subscriptions-per-connection &amp;lt;RPC_MAX_SUBSCRIPTIONS_PER_CONNECTION&amp;gt;              Set the maximum concurrent subscriptions per connection [default: 1024]
      --rpc-port &amp;lt;PORT&amp;gt;                                                                          Specify JSON-RPC server TCP port
      --rpc-max-connections &amp;lt;COUNT&amp;gt;                                                              Maximum number of RPC server connections [default: 100]
      --rpc-message-buffer-capacity-per-connection &amp;lt;RPC_MESSAGE_BUFFER_CAPACITY_PER_CONNECTION&amp;gt;  The number of messages the RPC server is allowed to keep in memory [default: 64]
      --rpc-disable-batch-requests                                                               Disable RPC batch requests
      --rpc-max-batch-request-len &amp;lt;LEN&amp;gt;                                                          Limit the max length per RPC batch request
      --rpc-cors &amp;lt;ORIGINS&amp;gt;                                                                       Specify browser *origins* allowed to access the HTTP &amp;amp; WS RPC servers
      --name &amp;lt;NAME&amp;gt;                                                                              The human-readable name for this node
      --no-telemetry                                                                             Disable connecting to the Substrate telemetry server
      --telemetry-url &amp;lt;URL VERBOSITY&amp;gt;                                                            The URL of the telemetry server to connect to
      --prometheus-port &amp;lt;PORT&amp;gt;                                                                   Specify Prometheus exporter TCP Port
      --prometheus-external                                                                      Expose Prometheus exporter on all interfaces
      --no-prometheus                                                                            Do not expose a Prometheus exporter endpoint
      --max-runtime-instances &amp;lt;MAX_RUNTIME_INSTANCES&amp;gt;                                            The size of the instances cache for each runtime [max: 32] [default: 8]
      --runtime-cache-size &amp;lt;RUNTIME_CACHE_SIZE&amp;gt;                                                  Maximum number of different runtimes that can be cached [default: 2]
      --offchain-worker &amp;lt;ENABLED&amp;gt;                                                                Execute offchain workers on every block [default: when-authority] [possible values: always, never, when-authority]
      --enable-offchain-indexing &amp;lt;ENABLE_OFFCHAIN_INDEXING&amp;gt;                                      Enable offchain indexing API [default: false] [possible values: true, false]
      --chain &amp;lt;CHAIN_SPEC&amp;gt;                                                                       Specify the chain specification
      --dev                                                                                      Specify the development chain
  -d, --base-path &amp;lt;PATH&amp;gt;                                                                         Specify custom base path
  -l, --log &amp;lt;LOG_PATTERN&amp;gt;...                                                                     Sets a custom logging filter (syntax: `&amp;lt;target&amp;gt;=&amp;lt;level&amp;gt;`)
      --detailed-log-output                                                                      Enable detailed log output
      --disable-log-color                                                                        Disable log color output
      --enable-log-reloading                                                                     Enable feature to dynamically update and reload the log filter
      --tracing-targets &amp;lt;TARGETS&amp;gt;                                                                Sets a custom profiling filter
      --tracing-receiver &amp;lt;RECEIVER&amp;gt;                                                              Receiver to process tracing messages [default: log] [possible values: log]
      --state-pruning &amp;lt;PRUNING_MODE&amp;gt;                                                             Specify the state pruning mode
      --blocks-pruning &amp;lt;PRUNING_MODE&amp;gt;                                                            Specify the blocks pruning mode [default: archive-canonical]
      --database &amp;lt;DB&amp;gt;                                                                            Select database backend to use [possible values: rocksdb, paritydb, auto, paritydb-experimental]
      --db-cache &amp;lt;MiB&amp;gt;                                                                           Limit the memory the database cache can use
      --wasm-execution &amp;lt;METHOD&amp;gt;                                                                  Method for executing Wasm runtime code [default: compiled] [possible values: interpreted-i-know-what-i-do, compiled]
      --wasmtime-instantiation-strategy &amp;lt;STRATEGY&amp;gt;                                               The WASM instantiation method to use [default: pooling-copy-on-write] [possible values: pooling-copy-on-write, recreate-instance-copy-on-write, pooling,
                                                                                                 recreate-instance]
      --wasm-runtime-overrides &amp;lt;PATH&amp;gt;                                                            Specify the path where local WASM runtimes are stored
      --execution-syncing &amp;lt;STRATEGY&amp;gt;                                                             Runtime execution strategy for importing blocks during initial sync [possible values: native, wasm, both, native-else-wasm]
      --execution-import-block &amp;lt;STRATEGY&amp;gt;                                                        Runtime execution strategy for general block import (including locally authored blocks) [possible values: native, wasm, both, native-else-wasm]
      --execution-block-construction &amp;lt;STRATEGY&amp;gt;                                                  Runtime execution strategy for constructing blocks [possible values: native, wasm, both, native-else-wasm]
      --execution-offchain-worker &amp;lt;STRATEGY&amp;gt;                                                     Runtime execution strategy for offchain workers [possible values: native, wasm, both, native-else-wasm]
      --execution-other &amp;lt;STRATEGY&amp;gt;                                                               Runtime execution strategy when not syncing, importing or constructing blocks [possible values: native, wasm, both, native-else-wasm]
      --execution &amp;lt;STRATEGY&amp;gt;                                                                     The execution strategy that should be used by all execution contexts [possible values: native, wasm, both, native-else-wasm]
      --trie-cache-size &amp;lt;Bytes&amp;gt;                                                                  Specify the state cache size [default: 67108864]
      --state-cache-size &amp;lt;STATE_CACHE_SIZE&amp;gt;                                                      DEPRECATED: switch to `--trie-cache-size`
      --bootnodes &amp;lt;ADDR&amp;gt;...                                                                      Specify a list of bootnodes
      --reserved-nodes &amp;lt;ADDR&amp;gt;...                                                                 Specify a list of reserved node addresses
      --reserved-only                                                                            Whether to only synchronize the chain with reserved nodes
      --public-addr &amp;lt;PUBLIC_ADDR&amp;gt;...                                                             Public address that other nodes will use to connect to this node
      --listen-addr &amp;lt;LISTEN_ADDR&amp;gt;...                                                             Listen on this multiaddress
      --port &amp;lt;PORT&amp;gt;                                                                              Specify p2p protocol TCP port
      --no-private-ip                                                                            Always forbid connecting to private IPv4/IPv6 addresses
      --allow-private-ip                                                                         Always accept connecting to private IPv4/IPv6 addresses
      --out-peers &amp;lt;COUNT&amp;gt;                                                                        Number of outgoing connections we&apos;re trying to maintain [default: 8]
      --in-peers &amp;lt;COUNT&amp;gt;                                                                         Maximum number of inbound full nodes peers [default: 32]
      --in-peers-light &amp;lt;COUNT&amp;gt;                                                                   Maximum number of inbound light nodes peers [default: 100]
      --no-mdns                                                                                  Disable mDNS discovery (default: true)
      --max-parallel-downloads &amp;lt;COUNT&amp;gt;                                                           Maximum number of peers from which to ask for the same blocks in parallel [default: 5]
      --node-key &amp;lt;KEY&amp;gt;                                                                           Secret key to use for p2p networking
      --node-key-type &amp;lt;TYPE&amp;gt;                                                                     Crypto primitive to use for p2p networking [default: ed25519] [possible values: ed25519]
      --node-key-file &amp;lt;FILE&amp;gt;                                                                     File from which to read the node&apos;s secret key to use for p2p networking
      --discover-local                                                                           Enable peer discovery on local networks
      --kademlia-disjoint-query-paths                                                            Require iterative Kademlia DHT queries to use disjoint paths
      --kademlia-replication-factor &amp;lt;KADEMLIA_REPLICATION_FACTOR&amp;gt;                                Kademlia replication factor [default: 20]
      --ipfs-server                                                                              Join the IPFS network and serve transactions over bitswap protocol
      --sync &amp;lt;SYNC_MODE&amp;gt;                                                                         Blockchain syncing mode. [default: full] [possible values: full, fast, fast-unsafe, warp]
      --max-blocks-per-request &amp;lt;COUNT&amp;gt;                                                           Maximum number of blocks per request [default: 64]
      --pool-limit &amp;lt;COUNT&amp;gt;                                                                       Maximum number of transactions in the transaction pool [default: 8192]
      --pool-kbytes &amp;lt;COUNT&amp;gt;                                                                      Maximum number of kilobytes of all transactions stored in the pool [default: 20480]
      --tx-ban-seconds &amp;lt;SECONDS&amp;gt;                                                                 How long a transaction is banned for
      --keystore-path &amp;lt;PATH&amp;gt;                                                                     Specify custom keystore path
      --password-interactive                                                                     Use interactive shell for entering the password used by the keystore
      --password &amp;lt;PASSWORD&amp;gt;                                                                      Password used by the keystore
      --password-filename &amp;lt;PATH&amp;gt;                                                                 File that contains the password used by the keystore
      --alice                                                                                    Shortcut for `--name Alice --validator`
      --bob                                                                                      Shortcut for `--name Bob --validator`
      --charlie                                                                                  Shortcut for `--name Charlie --validator`
      --dave                                                                                     Shortcut for `--name Dave --validator`
      --eve                                                                                      Shortcut for `--name Eve --validator`
      --ferdie                                                                                   Shortcut for `--name Ferdie --validator`
      --one                                                                                      Shortcut for `--name One --validator`
      --two                                                                                      Shortcut for `--name Two --validator`
      --force-authoring                                                                          Enable authoring even when offline
      --tmp                                                                                      Run a temporary node
  -h, --help                                                                                     Print help (see more with &apos;--help&apos;)
  -V, --version                                                                                  Print version
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;运行本地节点&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;./target/release/solochain-template-node --dev --rpc-external  --rpc-cors all
# 运行节点后默认占用9944端口，并且因为这是本地开发节点，只支持本地RPC，ws
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;访问&lt;a href=&quot;https://polkadot.js.org/apps/#/explorer?rpc=ws://localhost:9944&quot;&gt;polkadotJS前端&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;访问前端页面，点击选择development的local node
https://polkadot.js.org/apps/#/explorer?rpc=ws://localhost:9944
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;获取内容&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/d40708f4210f24ec9e20ca363544ade4.png&quot; alt=&quot;chaininfo.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;查看账户&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/0a329c72087e6f31abd5ca3b1cbba647.png&quot; alt=&quot;conn-node.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;转账交易&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/7614d868ab58f17ab3a8a61165d36cda.png&quot; alt=&quot;transaction.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;交易信息&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/f112d9e11185be4a925d15d54a0f4d21.png&quot; alt=&quot;hash-info.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;由于官方提供的文档为英文，且文档中仓库信息发生过变更，我手动将doc.substrate.io翻译为中文了，为不熟悉英文的朋友提供帮助&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://substrate-docs.pages.dev/en/tutorials/build-a-blockchain/?mode=light&quot;&gt; Substrate中文文档(非官方)&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>实时监控钱包交易系统设计文档</title><link>https://blog.ithuo.net/posts/design-document-realtime-cryptocurrency-wallet-monitoring/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/design-document-realtime-cryptocurrency-wallet-monitoring/</guid><pubDate>Mon, 21 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;:::tip&lt;/p&gt;
&lt;p&gt;本项目是一个用 Rust 编写的命令行工具，核心功能是通过监听新区块并分析其中的交易数据来监控钱包活动。它利用交易收据、调用跟踪和日志信息来追踪代币转移并计算损益。程序设计重点在于 MEV（最大化可提取价值）分析，它能够追踪 builder 奖励和验证者贿赂。通过异步编程和高效的数据结构，实时监控多个链上的多个钱包并将交易消息即时通知到Telegram。&lt;/p&gt;
&lt;p&gt;以下是该项目的主要功能和实现原理：&lt;/p&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;h2&gt;主要功能&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;配置加载&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;程序从 YAML 配置文件中加载监控的区块链、钱包地址以及 Telegram 通知设置。配置文件定义了要监控的链的 RPC URL、每个钱包的地址、关联的 builder 地址（用于 MEV 分析）、其他相关地址，以及是否包含接收方地址到损益计算中。&lt;/li&gt;
&lt;li&gt;支持容器化部署&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;区块处理&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;WalletWatcher 使用提供的区块链 provider 连接到指定的链，并在每个新区块到达时处理。它获取区块中的所有交易的收据和跟踪信息，以便进行后续分析。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;损益计算&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;对于每个钱包，&lt;code&gt;process_block&lt;/code&gt; 函数调用 &lt;code&gt;generate_pnl&lt;/code&gt; 函数来计算该区块内的损益。此函数分析交易日志和调用跟踪，以追踪原生代币和 ERC20 代币的转移，并计算交易费用，考虑 builder 奖励和验证者贿赂（针对 MEV 场景）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;消息生成与发送&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;根据计算出的损益和代币变化，&lt;code&gt;message_generator&lt;/code&gt; 生成包含相关信息的消息，例如交易哈希、代币数量变化等。然后程序调用 Telegram Bot API 将消息发送到配置的群组中。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;命令行界面&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;项目提供了 &lt;code&gt;start&lt;/code&gt;、&lt;code&gt;run&lt;/code&gt; 和 &lt;code&gt;backtest&lt;/code&gt; 命令，以便用户启动实时监控、执行特定操作或基于历史数据进行回测分析。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;区块处理&lt;/h2&gt;
&lt;p&gt;wallet-watcher 项目的区块处理主要由 &lt;code&gt;src/processor.rs&lt;/code&gt; 文件中的 &lt;code&gt;process_block&lt;/code&gt; 函数实现，其详细步骤如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;初始化&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;函数接收链 ID、区块头信息、交易收据和调用跟踪数据，以及要监控的钱包列表作为输入。它初始化一个向量 &lt;code&gt;reports&lt;/code&gt; 用于存储每个钱包的损益报告。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;收集所有相关地址&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;程序收集所有涉及的钱包地址，包括被监控钱包的地址、与其相关的其他地址，以及交易的接收方地址（如果配置中开启了 &lt;code&gt;include_recipient&lt;/code&gt; 选项）。这确保了程序能够追踪所有与被监控钱包相关的资金流动。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;遍历交易和调用跟踪&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;程序遍历区块中的每一笔交易及其对应的调用跟踪信息。对于每笔交易，它调用 &lt;code&gt;generate_pnl&lt;/code&gt; 函数计算该交易产生的余额变化，并将结果存储在 &lt;code&gt;balance_changes_all&lt;/code&gt; 向量中。该函数会分析交易日志和调用跟踪，以追踪代币转移，包括原生代币和 ERC20 代币的转移，并处理 WETH 的存取款。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;过滤无关交易&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;程序会过滤掉与被监控钱包无关的交易，以及疑似空气投币的交易（使用 &lt;code&gt;is_shitcoin_airdrop&lt;/code&gt; 函数识别此类交易）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;计算每个钱包的损益&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;对于每个被监控的钱包，程序会遍历所有与其相关的交易，并计算总交易费用和代币余额变化。它还会根据配置信息判断该钱包是否为 builder，如果是，则计算 builder 奖励和验证者贿赂。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生成损益报告&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;最后程序将计算出的损益、代币余额变化、builder 奖励和验证者贿赂等信息汇总到 &lt;code&gt;PnlReport&lt;/code&gt; 结构体中，并将其添加到 &lt;code&gt;reports&lt;/code&gt; 向量中。如果某个钱包在该区块内没有发生任何相关交易，则对应的报告为空。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;核心逻辑&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;process_block&lt;/code&gt; 函数通过对区块数据进行细致分析，实现了对钱包活动的全面监控和损益计算。它特别处理了 builder 奖励和验证者贿赂，以支持 MEV 分析。总体而言，该函数通过遍历区块中的每一笔交易，分析与被监控钱包相关的数据流动，从而实现精确的财务报告。&lt;/p&gt;
&lt;h2&gt;配置读取&lt;/h2&gt;
&lt;p&gt;wallet-watcher 项目需要配置链节点 RPC 地址，通过这些地址读取和遍历区块：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;RPC 配置&lt;/strong&gt;：
在 &lt;code&gt;src/config.rs&lt;/code&gt; 文件中，&lt;code&gt;Config&lt;/code&gt; 结构体包含一个 &lt;code&gt;chains&lt;/code&gt; 字段，它是一个 HashMap，用于存储链名称及对应的 RPC URL。例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;chains:  mainnet: &quot;https://eth-mainnet.alchemyapi.io/v2/your-api-key&quot;  optimism: &quot;https://optimism-mainnet.alchemyapi.io/v2/your-api-key&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;区块读取与遍历&lt;/strong&gt;：
在 &lt;code&gt;src/main.rs&lt;/code&gt; 文件中，程序会读取配置文件，并根据配置创建对应链的信息。在这里，使用 alloy 库提供 HTTP 或 WebSocket provider 来连接到指定 RPC URL。当有新的区块产生时，WalletWatcher 的 &lt;code&gt;process_event&lt;/code&gt; 函数会被调用，从而获取最新区块的信息并进行处理。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;wallet-watcher 通过以下步骤读取和遍历区块：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;从配置文件中读取链的 RPC URL。&lt;/li&gt;
&lt;li&gt;使用 alloy 库创建与区块链节点之间的连接。&lt;/li&gt;
&lt;li&gt;监听新区块事件。&lt;/li&gt;
&lt;li&gt;获取新区块中的交易收据和调用跟踪数据。&lt;/li&gt;
&lt;li&gt;遍历这些交易数据并分析钱包活动。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;因此wallet-watcher 依赖于用户提供的 RPC URL 来连接到区块链节点（建议自建节点），并使用 alloy 库提供功能来读取和遍历区块数据。&lt;/p&gt;
&lt;h2&gt;损益计算&lt;/h2&gt;
&lt;p&gt;本项目的损益计算主要通过 &lt;code&gt;src/processor.rs&lt;/code&gt; 文件中的 &lt;code&gt;generate_pnl&lt;/code&gt; 和 &lt;code&gt;process_block&lt;/code&gt; 函数实现。以下是详细过程：&lt;/p&gt;
&lt;h3&gt;generate_pnl 函数&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;此函数接收链 ID、交易收据、调用跟踪信息以及可选地址集合作为输入。&lt;/li&gt;
&lt;li&gt;它首先创建一个 &lt;code&gt;BalanceChanges&lt;/code&gt; 结构体，用于存储发生在交易中的余额变化。&lt;/li&gt;
&lt;li&gt;遍历调用跟踪中的每一个调用帧，并检查是否有错误或回滚。&lt;/li&gt;
&lt;li&gt;对于每个调用帧，它会遍历其中日志，并尝试解码 ERC20 Transfer 事件或 WETH Deposit 和 Withdrawal 事件。如果解码成功，它会记录代币转移信息，包括代币地址、发送方地址、接收方地址及转移数量。&lt;/li&gt;
&lt;li&gt;对于原生代币转移，会检查调用帧类型并记录相应转移信息。&lt;/li&gt;
&lt;li&gt;最后，它会过滤掉余额为零的转移，并返回 &lt;code&gt;BalanceChanges&lt;/code&gt; 结构体。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;process_block 函数&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;此函数接收链 ID、区块头信息、交易收据及调用跟踪数据，以及要监控的钱包列表作为输入。&lt;/li&gt;
&lt;li&gt;它首先遍历区块中的每一笔交易，并调用 &lt;code&gt;generate_pnl&lt;/code&gt; 函数计算该笔交易产生的余额变化。&lt;/li&gt;
&lt;li&gt;然后过滤掉与被监控钱包无关及疑似空气投币的交易。&lt;/li&gt;
&lt;li&gt;对于每个被监控的钱包，遍历所有相关交易并计算总交易费用及代币余额变化。此处，交易费用通过 &lt;code&gt;calculate_tx_fee&lt;/code&gt; 函数计算，该函数考虑 gas 使用量及 gas 价格，以及 L1 网络费用（如 Optimism 等 L2 网络）。&lt;/li&gt;
&lt;li&gt;最终生成一个 &lt;code&gt;PnlReport&lt;/code&gt; 结构体，其中包含完整的损益报告，包括各类费用及奖励信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;损益计算核心逻辑&lt;/h3&gt;
&lt;p&gt;wallet-watcher 的损益计算核心逻辑包括：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;分析交易日志及调用跟踪以追踪代币转移。&lt;/li&gt;
&lt;li&gt;精确计算各类费用。&lt;/li&gt;
&lt;li&gt;合并所有相关地址余额变化以得出准确结果。&lt;/li&gt;
&lt;li&gt;综合考虑 builder 奖励及验证者贿赂以确保报告完整性。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;通过这些步骤，wallet-watcher 能够准确地反映出每个被监控钱包在每个区块内所产生的财务状况。&lt;/p&gt;
&lt;h2&gt;消息生成与发送&lt;/h2&gt;
&lt;p&gt;wallet-watcher 项目的消息生成与发送功能主要通过 &lt;code&gt;src/message.rs&lt;/code&gt; 文件中的 &lt;code&gt;MessageGenerator&lt;/code&gt; 结构体以及 &lt;code&gt;burberry&lt;/code&gt; 库实现。以下是详细的实现过程：&lt;/p&gt;
&lt;h3&gt;MessageGenerator 结构体&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;src/message.rs&lt;/code&gt; 文件中，定义了 &lt;code&gt;MessageGenerator&lt;/code&gt; 结构体，它负责根据区块数据和损益报告生成消息。该结构体持有链 ID 和区块链 provider 的引用，以便于获取相关信息。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;加载代币符号和小数位数&lt;/strong&gt;：使用 &lt;code&gt;load_symbol_and_decimal&lt;/code&gt; 函数加载代币的符号和小数位数，以便在消息中格式化代币数量。这一步骤对于确保消息的可读性至关重要，因为不同代币可能具有不同的小数位数。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;generate 函数&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;MessageGenerator&lt;/code&gt; 的 &lt;code&gt;generate&lt;/code&gt; 函数接收区块信息、交易收据、调用跟踪数据、损益报告以及钱包信息作为输入。该函数的主要步骤包括：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;生成文本消息&lt;/strong&gt;：根据输入的信息生成包含交易哈希、代币数量变化、损益等信息的文本消息。它会使用 &lt;code&gt;utils&lt;/code&gt; 模块中的函数来格式化地址、交易哈希和代币数量，并生成指向区块浏览器和 Phalcon 的链接。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;包含额外信息&lt;/strong&gt;：根据配置信息，决定是否包含 builder 奖励和验证者贿赂等信息。这使得用户能够一目了然地看到与其钱包活动相关的所有重要信息。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;burberry 库&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;burberry&lt;/code&gt; 库提供了发送消息的功能，wallet-watcher 使用 &lt;code&gt;burberry::executor::telegram_message::MessageBuilder&lt;/code&gt; 来构建消息。在 &lt;code&gt;src/strategy.rs&lt;/code&gt; 文件中，WalletWatcher 的 &lt;code&gt;process_block&lt;/code&gt; 函数会调用 &lt;code&gt;MessageGenerator&lt;/code&gt; 的 &lt;code&gt;generate&lt;/code&gt; 函数生成消息。然后，它会使用 &lt;code&gt;MessageBuilder&lt;/code&gt; 设置 Telegram Bot 的 token、chat ID 和 thread ID（如果配置了）。最后，它会调用 &lt;code&gt;submitter.submit&lt;/code&gt; 函数将消息发送到 Telegram。&lt;/p&gt;
&lt;h3&gt;消息生成与发送的核心逻辑&lt;/h3&gt;
&lt;p&gt;wallet-watcher 的消息生成与发送核心逻辑如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;使用 MessageGenerator&lt;/strong&gt;：根据区块数据和损益报告生成文本消息。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;构建消息&lt;/strong&gt;：使用 &lt;code&gt;burberry::executor::telegram_message::MessageBuilder&lt;/code&gt; 构建消息，并设置 Telegram Bot 的相关信息。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;发送消息&lt;/strong&gt;：使用 &lt;code&gt;submitter.submit&lt;/code&gt; 函数将消息发送到 Telegram。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;通过这些步骤，wallet-watcher 能够将监控到的钱包活动和损益信息以文本消息的形式发送到 Telegram，从而帮助用户及时了解其钱包的财务状况。&lt;/p&gt;
&lt;h2&gt;回测功能实现&lt;/h2&gt;
&lt;p&gt;wallet-watcher 项目的回测功能允许用户基于历史数据进行回测分析，其实现方式如下：&lt;/p&gt;
&lt;h3&gt;读取测试数据&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;src/cli/backtest.rs&lt;/code&gt; 文件中，定义了回测命令的参数，包括测试数据文件的路径 (&lt;code&gt;test_data&lt;/code&gt;) 和 RPC URL (&lt;code&gt;rpc_url&lt;/code&gt;)。具体步骤如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;打开测试数据文件&lt;/strong&gt;：回测命令的 &lt;code&gt;run&lt;/code&gt; 函数首先打开指定的测试数据文件。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解析 YAML 数据&lt;/strong&gt;：使用 &lt;code&gt;serde_yaml&lt;/code&gt; 库将文件内容解析为 &lt;code&gt;TestCase&lt;/code&gt; 结构体的向量。每个测试用例包括区块号、钱包地址、builder 地址、其他相关地址、是否包含接收方以及预期的损益报告。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;创建区块链 provider&lt;/h3&gt;
&lt;p&gt;在读取完测试数据后，回测命令会使用提供的 RPC URL 创建一个区块链 provider。这一过程确保 wallet-watcher 能够连接到指定的区块链节点，以获取必要的数据进行分析。&lt;/p&gt;
&lt;h3&gt;并行处理测试用例&lt;/h3&gt;
&lt;p&gt;回测命令利用异步编程并行处理多个测试用例。具体步骤包括：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;创建异步任务&lt;/strong&gt;：使用 &lt;code&gt;tokio::spawn&lt;/code&gt; 创建多个异步任务，每个任务处理一个测试用例。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;调用 worker 函数&lt;/strong&gt;：每个任务都会调用 &lt;code&gt;worker&lt;/code&gt; 函数，该函数首先获取指定区块的交易收据和调用跟踪数据。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;获取区块头信息&lt;/strong&gt;：然后会获取指定区块的区块头信息，并调用 &lt;code&gt;processor::process_block&lt;/code&gt; 函数来计算该区块的损益报告。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;结果比较&lt;/strong&gt;：最后会将计算出的损益报告与测试用例中预期的损益报告进行比较，以验证 wallet-watcher 的计算逻辑是否正确。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;结果验证与输出&lt;/h3&gt;
&lt;p&gt;在所有测试用例处理完毕后，回测命令会接收每个任务的执行结果，并根据结果进行验证和输出。具体步骤如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;生成新测试用例&lt;/strong&gt;：如果参数设置为 true，则将计算出的损益报告写入到测试数据文件中，用于生成新的测试用例。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;比较预期结果&lt;/strong&gt;：如果参数设置为 false，则将计算出的损益报告与预期结果进行比较，并输出测试结果。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;调试输出&lt;/strong&gt;：如果测试结果不匹配，则输出调试命令，以便用户可以手动运行该测试用例进行调试。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;回测命令核心原理&lt;/h3&gt;
&lt;p&gt;回测命令的核心原理如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;从 YAML 文件中读取测试用例，包括区块号、钱包地址和预期的损益报告。&lt;/li&gt;
&lt;li&gt;使用提供的 RPC URL 连接到区块链节点。&lt;/li&gt;
&lt;li&gt;并行处理每个测试用例，获取指定区块的交易数据，并计算损益。&lt;/li&gt;
&lt;li&gt;将计算出的损益与预期结果进行比较，并输出测试结果。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;通过这些步骤，backtest 命令可以基于历史数据进行回测分析，验证 wallet-watcher 项目的损益计算逻辑是否正确。&lt;/p&gt;
&lt;h2&gt;日志处理&lt;/h2&gt;
&lt;p&gt;本项目选择不将链下处理的数据存储到数据库（如 ClickHouse 或 PostgreSQL），而是将数据输出到日志中进行处理和分析。这一选择背后的原因及具体实现逻辑如下：&lt;/p&gt;
&lt;h3&gt;为什么没有使用数据库？&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;简化架构&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;使用日志可以简化项目架构，避免引入数据库所带来的复杂性。这使得项目更容易部署和维护，同时降低了开发成本。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;快速原型开发&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;对于快速原型开发而言，使用日志可以更快地迭代和测试，使开发者能够专注于功能实现，而不必担心数据库管理的问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;灵活性&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;日志提供了灵活的数据分析方式，可以使用各种工具进行过滤、搜索和聚合，从而支持多样化的数据分析需求。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;日志分析工具&lt;/h3&gt;
&lt;p&gt;用户可以利用现有的日志分析工具（例如 Elasticsearch、Splunk 和 Grafana Loki）来处理和分析日志数据。这些工具能够帮助用户实时监控系统状态，并对日志进行深入分析。&lt;/p&gt;
&lt;h3&gt;日志输出与处理逻辑&lt;/h3&gt;
&lt;p&gt;使用 Rust 的 &lt;code&gt;tracing&lt;/code&gt; 库进行日志输出，该库提供了结构化日志记录功能，使得日志更易于过滤和分析。以下是具体实现细节：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;记录损益与交易信息&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;在 &lt;code&gt;src/strategy.rs&lt;/code&gt; 中，WalletWatcher 的 &lt;code&gt;process_block&lt;/code&gt; 函数使用 &lt;code&gt;tracing::info!&lt;/code&gt; 记录每个钱包的损益、代币变化和交易信息。同时，在处理过程中发生错误时，会使用 &lt;code&gt;tracing::error!&lt;/code&gt; 记录错误信息，以便后续排查问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;创建处理过程 span&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;在 &lt;code&gt;src/processor.rs&lt;/code&gt; 中，&lt;code&gt;process_block&lt;/code&gt; 函数使用 &lt;code&gt;info_span!&lt;/code&gt; 创建一个 span，用于记录每个钱包在处理过程中的状态。这种结构化的方法使得追踪特定操作变得更加清晰。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;详细调试信息记录&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;在生成损益报告时，调用跟踪中的详细信息（如交易索引、交易哈希、费用等）会通过 &lt;code&gt;tracing::trace!&lt;/code&gt; 记录下来。这有助于开发者在调试时获得更全面的信息，从而快速定位问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><author>Derick</author></item><item><title>监控EVM交易数据分析工具设计</title><link>https://blog.ithuo.net/posts/building-evm-transaction-monitoring-system/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/building-evm-transaction-monitoring-system/</guid><pubDate>Thu, 19 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;:::tip&lt;/p&gt;
&lt;p&gt;上个月完成了一个链下数据分析工具，现将详细设计文档记录，工具设计并不复杂，因数据分析对API调用次数较高，建议自建节点。&lt;/p&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;h2&gt;项目介绍&lt;/h2&gt;
&lt;p&gt;本工具是一个用于分析EVM链中特定区块并行交易执行的工具。监控链上出块数据，存入click house中跟踪交易状态，识别有价值的交易数据，目标是支持所有与EVM兼容的链，帮助交易员快速跟踪交易并监控执行。&lt;/p&gt;
&lt;h2&gt;功能介绍&lt;/h2&gt;
&lt;p&gt;本工具的主要功能包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;区块数据获取&lt;/strong&gt;: 从指定的EVM兼容链获取区块数据，包括区块头和交易列表。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;交易状态追踪&lt;/strong&gt;: 追踪每笔交易的执行状态，包括读取和写入的账户状态。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;交易依赖分析&lt;/strong&gt;: 分析同一区块内交易之间的依赖关系，确定哪些交易可以并行执行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API服务&lt;/strong&gt;: 提供API接口，用于查询分析结果，包括交易依赖图和并行分析器状态。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;架构设计&lt;/h2&gt;
&lt;p&gt;该项目主要由以下几个模块组成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;config&lt;/code&gt;&lt;/strong&gt;: 负责加载和管理配置信息，包括执行API地址、起始区块号、服务器地址和数据库URL。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;log&lt;/code&gt;&lt;/strong&gt;: 负责初始化日志系统。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;main&lt;/code&gt;&lt;/strong&gt;: 项目的入口点，负责启动并行分析器和API服务器。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;parallel_analyzer&lt;/code&gt;&lt;/strong&gt;: 核心模块，负责获取区块数据、追踪交易状态和分析交易依赖关系。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;server&lt;/code&gt;&lt;/strong&gt;: 使用&lt;code&gt;axum&lt;/code&gt;框架构建的API服务器，提供查询分析结果的接口。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;db&lt;/code&gt;&lt;/strong&gt;: 负责与数据库交互，包括区块、交易、交易依赖图和并行分析器状态的存储和查询。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;handlers&lt;/code&gt;&lt;/strong&gt;: 负责处理API请求，包括健康检查、交易依赖图查询和并行分析器状态查询。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;models&lt;/code&gt;&lt;/strong&gt;: 定义数据模型，包括区块、交易和交易依赖图。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;code&gt;parallel_analyzer&lt;/code&gt; 模块详解&lt;/h2&gt;
&lt;h3&gt;功能设计&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;parallel_analyzer&lt;/code&gt; 模块是整个项目的核心，负责实现以下功能：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;初始化&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;接收数据库连接、执行API地址、起始区块号和链ID作为参数。&lt;/li&gt;
&lt;li&gt;创建与执行API的连接客户端。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;区块数据获取&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;根据区块号，从执行API获取完整的区块数据，包括区块头和交易列表。&lt;/li&gt;
&lt;li&gt;将区块数据和交易数据存储到数据库中。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;交易状态追踪&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;使用执行API的&lt;code&gt;debug_trace_transaction&lt;/code&gt;方法，获取每笔交易的执行状态。&lt;/li&gt;
&lt;li&gt;通过&lt;code&gt;PreStateConfig&lt;/code&gt;配置，分别获取交易执行前的状态和执行后的状态差异。&lt;/li&gt;
&lt;li&gt;将账户状态转换为&lt;code&gt;StateSet&lt;/code&gt;，包括余额、代码和存储的读取和写入集合。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;交易依赖分析&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;遍历同一区块内的所有交易，比较每笔交易的读取集合和之前交易的写入集合。&lt;/li&gt;
&lt;li&gt;如果存在交集，则认为存在依赖关系，并记录到交易依赖图中。&lt;/li&gt;
&lt;li&gt;依赖关系类型包括余额依赖、代码依赖和存储依赖。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;运行&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;从起始区块号开始，循环分析每个区块，直到最新区块。&lt;/li&gt;
&lt;li&gt;每次分析完一个区块，更新并行分析器状态。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;详细实现方式&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;数据结构&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ParallelAnalyzer&lt;/code&gt;: 主结构体，包含数据库连接、执行API客户端、起始区块号和链ID。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;StateSet&lt;/code&gt;: 表示账户状态的集合，包括余额集合、代码集合和存储集合。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TransactionStateSet&lt;/code&gt;: 表示交易的状态集合，包括读取集合和写入集合。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;new&lt;/code&gt;&lt;/strong&gt; &lt;strong&gt;方法&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;创建&lt;code&gt;ParallelAnalyzer&lt;/code&gt;实例，初始化执行API客户端。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;get_block_transactions&lt;/code&gt;&lt;/strong&gt; &lt;strong&gt;方法&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;使用&lt;code&gt;execution_api_client&lt;/code&gt;的&lt;code&gt;get_block_by_number&lt;/code&gt;方法，获取指定区块的完整数据。&lt;/li&gt;
&lt;li&gt;将区块数据存储到数据库的&lt;code&gt;block&lt;/code&gt;表中。&lt;/li&gt;
&lt;li&gt;将交易数据存储到数据库的&lt;code&gt;transaction&lt;/code&gt;表中。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;trace_transaction_state&lt;/code&gt;&lt;/strong&gt; &lt;strong&gt;方法&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;使用&lt;code&gt;execution_api_client&lt;/code&gt;的&lt;code&gt;debug_trace_transaction&lt;/code&gt;方法，获取交易的执行状态。&lt;/li&gt;
&lt;li&gt;第一次调用&lt;code&gt;debug_trace_transaction&lt;/code&gt;，使用默认的&lt;code&gt;PreStateConfig&lt;/code&gt;，获取交易执行前的状态。&lt;/li&gt;
&lt;li&gt;第二次调用&lt;code&gt;debug_trace_transaction&lt;/code&gt;，使用&lt;code&gt;diff_mode&lt;/code&gt;为&lt;code&gt;true&lt;/code&gt;的&lt;code&gt;PreStateConfig&lt;/code&gt;，获取交易执行后的状态差异。&lt;/li&gt;
&lt;li&gt;调用&lt;code&gt;account_state_to_set&lt;/code&gt;方法，将账户状态转换为&lt;code&gt;StateSet&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;返回包含读取集合和写入集合的&lt;code&gt;TransactionStateSet&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;analyse_block&lt;/code&gt;&lt;/strong&gt; &lt;strong&gt;方法&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;调用&lt;code&gt;get_block_transactions&lt;/code&gt;方法，获取区块的交易列表。&lt;/li&gt;
&lt;li&gt;遍历交易列表，调用&lt;code&gt;trace_transaction_state&lt;/code&gt;方法，获取每笔交易的状态集合。&lt;/li&gt;
&lt;li&gt;遍历交易状态集合，比较每笔交易的读取集合和之前交易的写入集合，使用&lt;code&gt;check_tx_dependency&lt;/code&gt;方法判断是否存在依赖关系。&lt;/li&gt;
&lt;li&gt;如果存在依赖关系，将依赖关系信息存储到数据库的&lt;code&gt;transaction_dag&lt;/code&gt;表中。&lt;/li&gt;
&lt;li&gt;更新并行分析器状态，包括最新分析的区块号和最新区块号。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;run&lt;/code&gt;&lt;/strong&gt; &lt;strong&gt;方法&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;从起始区块号开始，循环分析每个区块。&lt;/li&gt;
&lt;li&gt;每次分析完一个区块，将区块号加1。&lt;/li&gt;
&lt;li&gt;如果当前区块号大于最新区块号，则等待一段时间后继续分析。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;account_state_to_set&lt;/code&gt;&lt;/strong&gt; &lt;strong&gt;函数&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;将账户状态转换为&lt;code&gt;StateSet&lt;/code&gt;，包括余额集合、代码集合和存储集合。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;check_tx_dependency&lt;/code&gt;&lt;/strong&gt; &lt;strong&gt;函数&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;比较两个交易状态集合的读取集合和写入集合，判断是否存在依赖关系。&lt;/li&gt;
&lt;li&gt;如果存在余额依赖，则返回&lt;code&gt;0x1&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;如果存在代码依赖，则返回&lt;code&gt;0x10&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;如果存在存储依赖，则返回&lt;code&gt;0x100&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;如果不存在依赖关系，则返回&lt;code&gt;0&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;&lt;code&gt;handlers&lt;/code&gt; 模块详解&lt;/h2&gt;
&lt;h3&gt;功能设计&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;handlers&lt;/code&gt; 模块负责处理API请求，并将请求转发到相应的处理函数。它主要包含以下功能：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;通用处理&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;handle_panic&lt;/code&gt;: 处理服务器内部的panic错误，返回500状态码和错误信息。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;handle_404&lt;/code&gt;: 处理找不到资源的请求，返回404状态码和错误信息。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;health_check&lt;/code&gt;: 提供健康检查接口，用于检查服务器是否正常运行。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;交易依赖图处理&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;handle_transaction_dag&lt;/code&gt;: 处理查询交易依赖图的请求，返回指定区块的交易列表和依赖关系。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;并行分析器状态处理&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;handle_parallel_analyzer_state&lt;/code&gt;: 处理查询并行分析器状态的请求，返回当前分析器的状态信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;详细实现方式&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;common.rs&lt;/code&gt;&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;handle_panic&lt;/code&gt; 函数：
&lt;ul&gt;
&lt;li&gt;接收一个 &lt;code&gt;Box&amp;lt;dyn Any + Send + &apos;static&amp;gt;&lt;/code&gt; 类型的错误信息。&lt;/li&gt;
&lt;li&gt;尝试将错误信息转换为 &lt;code&gt;String&lt;/code&gt; 或 &lt;code&gt;&amp;amp;str&lt;/code&gt; 类型，获取详细的错误信息。&lt;/li&gt;
&lt;li&gt;记录错误日志，并返回500状态码和错误信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;handle_404&lt;/code&gt; 函数：
&lt;ul&gt;
&lt;li&gt;返回404状态码和默认的错误信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;health_check&lt;/code&gt; 函数：
&lt;ul&gt;
&lt;li&gt;接收 &lt;code&gt;ServerState&lt;/code&gt; 作为状态参数。&lt;/li&gt;
&lt;li&gt;返回200状态码和空的 &lt;code&gt;HealthResp&lt;/code&gt; 对象。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;transaction_dag.rs&lt;/code&gt;&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;handle_transaction_dag&lt;/code&gt; 函数：
&lt;ul&gt;
&lt;li&gt;接收 &lt;code&gt;ServerState&lt;/code&gt; 作为状态参数，以及 &lt;code&gt;TransactionDagQuery&lt;/code&gt; 作为查询参数。&lt;/li&gt;
&lt;li&gt;如果查询参数中包含 &lt;code&gt;block_number&lt;/code&gt;，则使用该区块号；否则，使用最新区块号减去10作为默认区块号。&lt;/li&gt;
&lt;li&gt;从数据库中获取指定区块号的交易列表和交易依赖图。&lt;/li&gt;
&lt;li&gt;将交易数据和依赖关系数据转换为 &lt;code&gt;TransactionDagResponse&lt;/code&gt; 对象，并返回。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;handle_parallel_analyzer_state&lt;/code&gt; 函数：
&lt;ul&gt;
&lt;li&gt;接收 &lt;code&gt;ServerState&lt;/code&gt; 作为状态参数。&lt;/li&gt;
&lt;li&gt;从数据库中获取当前链ID的并行分析器状态。&lt;/li&gt;
&lt;li&gt;将并行分析器状态转换为 &lt;code&gt;ParallelAnalyzerStateResp&lt;/code&gt; 对象，并返回。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;mod.rs&lt;/code&gt;&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;声明 &lt;code&gt;common&lt;/code&gt; 和 &lt;code&gt;transaction_dag&lt;/code&gt; 模块，使其内容可以被其他模块访问。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;交互逻辑&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;API请求&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;客户端发送API请求到服务器。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;axum&lt;/code&gt; 框架根据请求的路径，将请求路由到相应的处理函数。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据获取&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;处理函数从 &lt;code&gt;ServerState&lt;/code&gt; 中获取数据库连接和执行API客户端。&lt;/li&gt;
&lt;li&gt;处理函数使用数据库连接查询数据库，获取所需的数据。&lt;/li&gt;
&lt;li&gt;处理函数使用执行API客户端查询区块链数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据处理&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;处理函数将从数据库和区块链获取的数据转换为相应的响应对象。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API响应&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;处理函数将响应对象转换为JSON格式，并返回给客户端。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;功能实现原理&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;数据获取&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;通过配置的执行API地址，使用&lt;code&gt;alloy&lt;/code&gt;库获取指定区块的完整数据，包括区块头和交易列表。&lt;/li&gt;
&lt;li&gt;将区块数据和交易数据存储到数据库中。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;交易状态追踪&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;使用&lt;code&gt;alloy&lt;/code&gt;库的&lt;code&gt;debug_trace_transaction&lt;/code&gt;方法，获取每笔交易的执行状态，包括读取和写入的账户状态。&lt;/li&gt;
&lt;li&gt;通过&lt;code&gt;PreStateConfig&lt;/code&gt;配置，分别获取交易执行前的状态和执行后的状态差异。&lt;/li&gt;
&lt;li&gt;将账户状态转换为&lt;code&gt;StateSet&lt;/code&gt;，包括余额、代码和存储的读取和写入集合。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;交易依赖分析&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;遍历同一区块内的所有交易，比较每笔交易的读取集合和之前交易的写入集合。&lt;/li&gt;
&lt;li&gt;如果存在交集，则认为存在依赖关系，并记录到交易依赖图中。&lt;/li&gt;
&lt;li&gt;依赖关系类型包括余额依赖、代码依赖和存储依赖。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API服务&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;使用&lt;code&gt;axum&lt;/code&gt;框架构建API服务器，提供以下接口：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/health&lt;/code&gt;: 健康检查接口。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/data/evm/transaction-dag&lt;/code&gt;: 查询交易依赖图接口。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/data/evm/parallel-analyzer-state&lt;/code&gt;: 查询并行分析器状态接口。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;使用&lt;code&gt;tower-http&lt;/code&gt;库提供CORS支持和panic处理。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><author>Derick</author></item><item><title>面向.NET开发者的Terraform入门指南:自动化AWS基础设施配置</title><link>https://blog.ithuo.net/posts/terraform-for-dotnet-developers-getting-started-with-aws-infrastructure-automation/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/terraform-for-dotnet-developers-getting-started-with-aws-infrastructure-automation/</guid><pubDate>Thu, 29 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Terraform是一个强大的工具,用于在多个云提供商中自动化基础设施的部署和管理。无论你是基础设施即代码的新手,还是想深入了解Terraform,本指南都将为你提供必要的知识和技能,以便在项目中有效地管理基础设施,不管你使用什么技术栈。Terraform是我在工作和个人项目中使用的工具,可以轻松地将应用程序基础设施部署到AWS云上。&lt;/p&gt;
&lt;h2&gt;基础设施即代码(IaC)&lt;/h2&gt;
&lt;p&gt;当你已经开始决定将所有应用程序的基础设施需求转移到云端后，下一步是高效地管理和配置该基础设施,这就是基础设施即代码(IaC)发挥作用的地方。IaC允许你使用代码自动创建、配置和管理云资源。这种方法确保了一致性、可重复性和可扩展性,使基础设施管理更加可靠,减少错误。&lt;/p&gt;
&lt;p&gt;无论你需要启动一个简单的Web应用程序还是编排一个复杂的多层架构,IaC都能让你轻松定义、部署和管理所有这些。在可用的IaC工具中,Terraform是最受欢迎的,也是最明显的选择。&lt;/p&gt;
&lt;h2&gt;Terraform简介&lt;/h2&gt;
&lt;p&gt;Terraform是当今最流行的IaC工具之一,允许你使用统一的语法管理多个云提供商的基础设施。无论你使用的是AWS、Azure、Google Cloud还是本地基础设施,Terraform的声明式语言都能让你以可扩展和可维护的方式定义资源和依赖关系。&lt;/p&gt;
&lt;h2&gt;安装Terraform&lt;/h2&gt;
&lt;p&gt;首先,让我们在你的机器上安装Terraform。请按照&lt;a href=&quot;https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli&quot;&gt;此文档&lt;/a&gt;中的说明进行安装。如果你使用Windows并想通过Chocolatey安装,请以管理员权限运行以下命令安装Chocolatey:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString(&apos;https://community.chocolatey.org/install.ps1&apos;))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装Chocolatey后,让我们安装Terraform:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;choco install terraform
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;你可以通过在命令行运行&lt;code&gt;terraform --version&lt;/code&gt;来验证安装。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/c935ca7f66f7ef0b0cecbc26a6223e3f.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在撰写本文时,最新的稳定版本是1.9.5。我们将主要使用Visual Studio Code编辑器来处理Terraform,因为它为编写此类脚本提供了最佳体验。请确保安装了以下扩展以改善你的开发体验:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;HashiCorp Terraform&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这将提供语法高亮、验证和建议等附加功能,使编写terraform文件变得更加顺畅。&lt;/p&gt;
&lt;h2&gt;Terraform提供者&lt;/h2&gt;
&lt;p&gt;Terraform提供者就像插件,指示Terraform使用特定的云提供商,如AWS、Azure、GCP等。请注意,使用Terraform也可以实现多云架构。但在本指南中,我们将保持简单。&lt;/p&gt;
&lt;p&gt;例如,如果你需要部署AWS S3存储桶,你需要使用AWS Terraform提供者。AWS提供者提供了一组资源,对应于AWS资源,如ECS、VPN等。截至今天,有超过200种AWS服务可用。&lt;/p&gt;
&lt;p&gt;首先,创建一个&lt;code&gt;providers.tf&lt;/code&gt;文件,并添加以下内容:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;terraform {
  required_version = &quot;~&amp;gt; 1.9.5&quot;
  required_providers {
    aws = {
      source  = &quot;hashicorp/aws&quot;
      version = &quot;~&amp;gt; 5.64.0&quot;
    }
  }
}

provider &quot;aws&quot; {
  region = &quot;us-east-1&quot;
  default_tags {
    tags = {
      Environment = &quot;staging&quot;
      Owner       = &quot;Mukesh Murugan&quot;
      Project     = &quot;codewithmukesh&quot;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在terraform块中,我们将定义所需的版本并将其设置为1.9.5,这是terraform的当前最新版本。接下来,我们将定义terraform aws提供者的版本,即5.64.0,这也是aws提供者的最新可用版本。&lt;/p&gt;
&lt;p&gt;在provider块中,我们将Area设置为&lt;code&gt;us-east-1&lt;/code&gt;,并提到一些默认标签,这些标签将添加到我们创建的每个资源中。我们将添加Environment、Owner和Project等标签。&lt;/p&gt;
&lt;p&gt;这指示Terraform使用AWS作为提供者,并将资源部署到&lt;code&gt;us-east-1&lt;/code&gt;区域。&lt;/p&gt;
&lt;h2&gt;在Terraform中编写你的第一个S3存储桶&lt;/h2&gt;
&lt;p&gt;现在我们已经添加了提供者,让我们编写我们的第一个资源,即AWS S3存储桶。创建一个&lt;code&gt;buckets.tf&lt;/code&gt;并添加以下内容:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;resource &quot;aws_s3_bucket&quot; &quot;codewithmukesh&quot; {
  bucket = &quot;codewithmukesh-bucket&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检查这段简单的代码。Terraform中S3存储桶的资源名称是&quot;aws_s3_bucket&quot;,这个特定资源的标识符是&quot;codewithmukesh&quot;。在这个资源块内,我们可以定义支持的S3存储桶属性,如名称和其他配置。你可以通过&lt;a href=&quot;https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket&quot;&gt;访问此链接&lt;/a&gt;了解此资源支持的其他属性。&lt;/p&gt;
&lt;p&gt;以下是步骤:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;决定创建资源A。&lt;/li&gt;
&lt;li&gt;你需要了解如何在云上手动创建资源A,以及与之相关的每个细节。&lt;/li&gt;
&lt;li&gt;导航到Terraform文档,在适当的提供者(在我们的例子中是AWS)下搜索你需要的资源。&lt;/li&gt;
&lt;li&gt;根据文档进行修改。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;**没有开发人员或DevOps工程师会(或被期望)记住每个资源脚本。**相反,文档应该始终被视为唯一的真相来源,因为它们会随着新版本的发布而变化。不要试图记忆terraform资源和语法,只需知道如何从文档中适应它们。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/50c305193e58a1210f7b4e1a9da2e4f2.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;例如,如果我想通过Terraform部署ECS服务,我会参考&lt;a href=&quot;https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service&quot;&gt;https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;到目前为止,我们已经编写了&lt;code&gt;terraform&lt;/code&gt;资源来部署AWS S3存储桶,但还没有部署它。在此之前,我们需要熟悉Terraform CLI命令和生命周期。&lt;/p&gt;
&lt;h2&gt;Terraform生命周期和CLI命令&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Terraform&lt;/code&gt;遵循特定的生命周期来管理基础设施即代码。以下是关键步骤和相应的CLI命令:&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;terraform init&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;此命令初始化Terraform工作目录。它下载必要的提供者插件,将它们安装在本地,并为进一步的命令准备项目。在新的项目目录中或在更改提供者或模块配置后,首先使用此命令。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;terraform plan&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;此命令创建一个执行计划,显示当你应用更改时Terraform将做什么。它比较当前状态与你的期望状态(在.tf文件中定义),并列出达到期望状态所需的操作。这对于分析和调试非常重要。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;terraform apply&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;此命令将计划的更改应用到基础设施。Terraform会在进行实际更改之前提示你批准执行计划。我倾向于使用&lt;code&gt;terraform apply -auto-approve&lt;/code&gt;来跳过提示。但是,请谨慎使用。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;terraform show&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;此命令显示当前状态或保存的计划的详细信息。它在应用更改后用于查看更改。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;terraform destroy&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;此命令销毁在Terraform文件中定义的管理基础设施。当你不再需要资源时使用它。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;terraform state&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;这组命令用于高级状态管理任务,如移动资源、删除资源或操作状态。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;terraform fmt&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;此命令将你的Terraform配置文件格式化为标准样式。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;terraform validate&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;此命令检查配置文件在语法上是否有效并且内部一致。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;terraform output&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;此命令显示配置中定义的输出变量的值。&lt;/p&gt;
&lt;h3&gt;工作流程&lt;/h3&gt;
&lt;p&gt;因此,在正常的工作流程中,你会这样部署资源:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;通过运行&lt;code&gt;terraform init&lt;/code&gt;初始化Terraform存储库。&lt;/li&gt;
&lt;li&gt;运行plan命令以查看将修改/添加或删除哪些资源。&lt;code&gt;terraform plan&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;一旦你对&lt;code&gt;plan&lt;/code&gt;命令的结果满意,你就会想通过运行&lt;code&gt;terraform apply&lt;/code&gt;命令将这些更改应用到你的实际基础设施。&lt;/li&gt;
&lt;li&gt;要销毁资源,运行&lt;code&gt;terraform destroy&lt;/code&gt;命令。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;验证Terraform以管理AWS中的资源&lt;/h2&gt;
&lt;p&gt;现在,有多种方法可以确保Terraform经过身份验证以代表你管理AWS资源。你可以修改&lt;code&gt;providers&lt;/code&gt;块以包含AWS凭证(Secret Key和Access Key),或使用AWS CLI配置文件来确保你的开发机器已通过身份验证。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;通过提供者块:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;provider &quot;aws&quot; {
  region     = &quot;us-west-2&quot;
  access_key = &quot;my-access-key&quot;
  secret_key = &quot;my-secret-key&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;虽然这是一种相当简单的方法,但存在许多安全问题,因为你现在将AWS Secret Key暴露给公众。但是,如果你只是测试东西,而不一定将任何代码推送到版本控制系统(如GitHub或GitLab),你可以使用这种方法。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;AWS CLI配置文件&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这是从本地机器使用Terraform的推荐方法。只需使用secret key/access key配置AWS CLI配置文件,并在Terraform中的AWS提供者块中引用AWS配置文件。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;provider &quot;aws&quot; {
  region  = &quot;us-west-2&quot;
  profile = &quot;mukesh&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在上述情况下,我配置了一个名为&lt;code&gt;mukesh&lt;/code&gt;的AWS CLI配置文件,并在提供者块下引用了它。这允许Terraform CLI使用AWS配置文件配置并验证到AWS以管理资源。你可以从&lt;a href=&quot;https://codewithmukesh.com/blog/aws-credentials-for-dotnet-applications/#install-aws-cli&quot;&gt;这里&lt;/a&gt;了解更多关于AWS CLI配置文件的信息。&lt;/p&gt;
&lt;h2&gt;部署 S3 存储桶&lt;/h2&gt;
&lt;p&gt;现在我们已经了解了工作流程会是什么样子,让我们尝试部署我们的第一个 S3 存储桶。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;首先通过运行 &lt;code&gt;terraform init&lt;/code&gt; 来初始化我们的 Terraform 脚本。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/c01d5ada2e7514e832031a761634ee6e.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这将下载 AWS Provider,并创建一些必要的 terraform 文件,如锁定文件和状态文件。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;接下来,运行 &lt;code&gt;terraform plan&lt;/code&gt; 命令。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/20c569140c4cb985b0d3d58b3e10cc37.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;执行命令后会显示变更集的详细信息,即将添加/修改或销毁的内容。在我们的例子中,它说 &lt;code&gt;aws_s3_bucket.codewithmukesh 将被创建&lt;/code&gt;,以及其内部属性。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;terraform plan&lt;/code&gt; 命令用于创建执行计划,本质上是 Terraform 将对基础设施进行的更改的预览。Terraform 检索基础设施的当前状态(从状态文件或实际基础设施),并将其与配置文件中定义的期望状态进行比较。基于比较,Terraform 确定使当前基础设施与期望状态一致所需的操作。这些操作可能包括创建、更新或删除资源。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;terraform plan&lt;/code&gt; 只生成计划;它不会对基础设施进行任何更改。它只是向你展示建议的更改,让你在应用之前进行审查。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;一旦你对 &lt;code&gt;terraform plan&lt;/code&gt; 的输出感到满意,运行 &lt;code&gt;terraform apply&lt;/code&gt; 来应用你的基础设施更改。在下一个提示中,输入 &lt;code&gt;yes&lt;/code&gt; 以确认部署。我通常使用 &lt;code&gt;terraform apply -auto-approve&lt;/code&gt; 来跳过这个确认提示。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/9e604a35ea6fb327b1c70297601c9235.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;如你所见,S3 存储桶已经配置完成。你也可以在 AWS 管理控制台上交叉检查这一点!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/b0bc7e6ebdc4fe81b36be33db1441dbf.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;现在我们已经成功通过 Terraform 部署了我们的第一个 AWS 资源,让我们学习 Terraform 中的变量和输出。&lt;/p&gt;
&lt;h2&gt;Terraform 变量&lt;/h2&gt;
&lt;p&gt;Terraform 中的变量允许你使配置文件更加灵活和可重用。通过使用变量,你可以参数化诸如资源名称、区域或实例类型等值。这样,你可以避免硬编码值,并且可以轻松修改配置,而无需更改实际的 &lt;code&gt;.tf&lt;/code&gt; 文件。&lt;/p&gt;
&lt;h3&gt;变量类型&lt;/h3&gt;
&lt;p&gt;Terraform 支持不同类型的变量,例如:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;字符串:&lt;/strong&gt; 单行文本。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数字:&lt;/strong&gt; 数值,如整数或浮点数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;布尔值:&lt;/strong&gt; 布尔值(&lt;code&gt;true&lt;/code&gt; 或 &lt;code&gt;false&lt;/code&gt;)。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;列表:&lt;/strong&gt; 有序的值序列(例如,&lt;code&gt;[&quot;a&quot;, &quot;b&quot;, &quot;c&quot;]&lt;/code&gt;)。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;映射:&lt;/strong&gt; 一组键值对(例如,&lt;code&gt;{key1 = &quot;value1&quot;, key2 = &quot;value2&quot;}&lt;/code&gt;)。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;定义变量&lt;/h3&gt;
&lt;p&gt;变量在 &lt;code&gt;.tf&lt;/code&gt; 文件中使用 &lt;code&gt;variable&lt;/code&gt; 块定义。让我们通过实施来学习这一点。创建一个名为 &lt;code&gt;variables.tf&lt;/code&gt; 的新文件,并添加以下内容:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;variable &quot;region&quot; {
  description = &quot;要部署资源的 AWS 区域&quot;
  type        = string
  default     = &quot;us-east-1&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;你可以在 Terraform 配置中使用语法 &lt;code&gt;var.{variable_name}&lt;/code&gt; 来引用变量。在我们的例子中,使用 &lt;code&gt;region&lt;/code&gt; 变量的正确位置是 &lt;code&gt;providers.tf&lt;/code&gt; 文件,我们在其中将 region 属性硬编码为 &lt;code&gt;us-east-1&lt;/code&gt;。你可以按如下方式修改 provider 块:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;provider &quot;aws&quot; {
  region = var.region
  default_tags {
    tags = {
      Environment = &quot;staging&quot;
      Owner       = &quot;Mukesh Murugan&quot;
      Project     = &quot;codewithmukesh&quot;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;设置变量&lt;/h3&gt;
&lt;p&gt;有多种方法可以设置变量值:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;默认值:在变量块中定义,如我们上面所做的那样。&lt;/li&gt;
&lt;li&gt;命令行标志:使用 -var 选项设置。这可以通过运行 &lt;code&gt;terraform apply -var=&quot;region=us-east-1&quot;&lt;/code&gt; 来完成。&lt;/li&gt;
&lt;li&gt;环境变量:使用 &lt;code&gt;TF_VAR_&lt;/code&gt; 环境变量。运行 &lt;code&gt;export TF_VAR_region=&quot;us-east-1&quot;&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;变量文件:使用 .tfvars 文件指定变量,并在运行时通过执行 &lt;code&gt;terraform apply -var-file=&quot;variables.tfvars&quot;&lt;/code&gt; 使用它。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在处理大型 Terraform 基础设施代码时,使用变量文件是我的首选方法。&lt;/p&gt;
&lt;h2&gt;Terraform 输出&lt;/h2&gt;
&lt;p&gt;Terraform 中的输出用于从你的配置中提取和显示有用的信息。它们帮助你在 Terraform 创建或更新基础设施后查看关键结果,如资源 ID、端点或连接字符串。&lt;/p&gt;
&lt;h3&gt;定义输出&lt;/h3&gt;
&lt;p&gt;你使用配置中的 output 块定义输出。例如,在我们的情况下,只需创建一个新的 output.tf 文件,其中包含以下代码:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;output &quot;bucket_name&quot; {
  description = &quot;S3 存储桶的名称&quot;
  value       = aws_s3_bucket.my_bucket.id
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输出会在 &lt;code&gt;terraform apply&lt;/code&gt; 命令完成后立即显示。以下是我应用 Terraform 更改后显示的内容:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/e9eeea434fb38a08210eb091bbfa46ba.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;你还可以使用 &lt;code&gt;terraform output&lt;/code&gt; 命令随时检索输出。&lt;/p&gt;
&lt;p&gt;通过利用变量和输出,你可以创建更加动态、可重用和模块化的 Terraform 配置。这提高了基础设施即代码的可维护性和可扩展性。&lt;/p&gt;
&lt;h2&gt;状态管理&lt;/h2&gt;
&lt;p&gt;Terraform 使用&lt;strong&gt;状态文件&lt;/strong&gt;来跟踪它管理的资源。状态文件存储有关你的基础设施的元数据,并作为 Terraform 的真实来源。当你运行 &lt;code&gt;terraform plan&lt;/code&gt; 或 &lt;code&gt;terraform apply&lt;/code&gt; 等命令时,Terraform 会将真实世界的基础设施与状态文件进行比较,以确定需要进行哪些更改。&lt;/p&gt;
&lt;p&gt;在terraform 目录中有额外的文件,如 &lt;code&gt;terraform.tfstate&lt;/code&gt;、&lt;code&gt;terraform.tfstate.backup&lt;/code&gt; 等。&lt;/p&gt;
&lt;h3&gt;为什么状态很重要?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;跟踪资源:&lt;/strong&gt; Terraform 需要状态文件来将真实资源映射到你的配置。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能:&lt;/strong&gt; Terraform 使用状态文件来高效计算更改,而不是从云提供商查询每个资源。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;协作:&lt;/strong&gt; 在团队工作时,正确管理状态对于确保基础设施更改的一致性至关重要。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;使用 S3 和 DynamoDB 的远程后端&lt;/h2&gt;
&lt;p&gt;默认情况下,Terraform 将其状态文件存储在本地。然而,对于生产环境或团队协作,将状态存储在远程&lt;strong&gt;后端&lt;/strong&gt;中更可靠。最常见的后端之一是 &lt;strong&gt;Amazon S3&lt;/strong&gt;。当你将状态存储在 S3 中时,它可以在团队成员之间共享,并受到保护,避免意外的本地删除。&lt;/p&gt;
&lt;p&gt;最常见的选择是将状态存储在 Amazon S3 中,使用 DynamoDB 进行状态锁定,以防止可能损坏状态的并发操作。&lt;/p&gt;
&lt;h3&gt;使用 S3 和 DynamoDB 设置远程后端&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;创建 S3 存储桶&lt;/strong&gt;
首先,在 AWS 中创建一个 S3 存储桶来存储你的 Terraform 状态文件。存储桶应该是私有的,并且应该启用版本控制,以便在状态损坏的情况下进行回滚。我将手动创建一个名为 &lt;code&gt;cwm-tfstates&lt;/code&gt; 的新存储桶用于此目的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;创建用于状态锁定的 DynamoDB 表&lt;/strong&gt;
为了防止多个 Terraform 进程同时修改状态,我们使用 DynamoDB 进行状态锁定。DynamoDB 确保一次只能运行一个操作,有助于避免状态损坏。我使用管理控制台创建了一个名为 &lt;code&gt;cwm-state-locks&lt;/code&gt; 的新 DynamoDB 表,分区键为 &lt;code&gt;LockID&lt;/code&gt;(字符串)。这个表将处理锁定,确保状态的安全并发使用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;资源清理&lt;/strong&gt;
运行 &lt;code&gt;terraform destroy&lt;/code&gt; 命令,确保你的资源已清理,并删除 &lt;code&gt;terraform.tfstate&lt;/code&gt; 文件。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;在 Terraform 中配置后端:&lt;/strong&gt;
在你的 Terraform 配置中,使用 backend 块来定义 S3 存储桶作为你的远程后端。创建一个名为 &lt;code&gt;main.tf&lt;/code&gt; 的新文件,并添加以下内容:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;terraform {
  backend &quot;s3&quot; {
    bucket         = &quot;cwm-tfstates&quot;
    key            = &quot;demo/beginners-guide/terraform.tfstate&quot;
    region         = &quot;us-east-1&quot;
    dynamodb_table = &quot;cwm-state-locks&quot;
    encrypt        = true
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;bucket 属性指定存储状态文件的 S3 存储桶。&lt;/li&gt;
&lt;li&gt;key 属性指定存储桶内状态文件的路径和名称。&lt;/li&gt;
&lt;li&gt;region 定义存储桶和 DynamoDB 表所在的位置。&lt;/li&gt;
&lt;li&gt;dynamodb_table 属性确保状态锁定由 DynamoDB 处理。&lt;/li&gt;
&lt;li&gt;encrypt 属性确保状态文件在 S3 中静态加密。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;初始化后端
在配置中定义后端后,你需要初始化 Terraform 以设置远程后端。这可以通过运行 &lt;code&gt;terraform init&lt;/code&gt; 命令来完成。但在此之前,运行 &lt;code&gt;terraform destroy&lt;/code&gt; 命令确保你的资源已清理,并删除 &lt;code&gt;terraform.tfstate&lt;/code&gt; 文件。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/12fa53a8c0c6a9379fd09c13f6c5b4d4.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;如图所示,我们的 S3 后端现在已成功配置,并带有 DynamoDB 表。从现在开始,当运行 &lt;code&gt;terraform plan&lt;/code&gt; 或 &lt;code&gt;terraform apply&lt;/code&gt; 时,terraform 将交叉检查远程后端(s3 和 dynamodb)中存在的状态文件,以决定如何修改资源。每次运行 &lt;code&gt;terraform apply&lt;/code&gt; 命令时,S3 上可用的状态文件都会更新。&lt;/p&gt;
&lt;h3&gt;使用 S3 和 DynamoDB 进行远程状态管理的好处&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;协作:多个团队成员可以访问和修改状态文件而不会发生冲突,这要归功于 S3 中的集中存储和 DynamoDB 中的状态锁定。&lt;/li&gt;
&lt;li&gt;一致性:状态存储在可靠和安全的远程位置,减少了数据丢失或意外删除的机会。&lt;/li&gt;
&lt;li&gt;安全性:S3 允许你为状态文件启用加密和版本控制,而 DynamoDB 通过在使用期间锁定状态确保安全的状态操作。&lt;/li&gt;
&lt;li&gt;审计:S3 中的版本控制使回滚到以前的状态成为可能,使审计基础设施更改和从问题中恢复变得容易。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这种状态管理方法对于生产环境至关重要,在这些环境中,你需要确保你的基础设施得到一致管理,并且不受并发问题的影响。将 S3 和 DynamoDB 结合使用,创建了一个强大的系统来管理和锁定你的 Terraform 状态。&lt;/p&gt;
&lt;h2&gt;部署 EC2 实例&lt;/h2&gt;
&lt;p&gt;现在我们已经清楚了所有基本概念,继续做一个小练习,通过 Terraform 部署一个新的 EC2 实例。创建一个名为 &lt;code&gt;ec2.tf&lt;/code&gt; 的新文件,并尝试从 terraform 文档中找出所需的代码。你需要添加以下内容:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;resource &quot;aws_instance&quot; &quot;demo&quot; {
  ami           = &quot;ami-066784287e358dad1&quot;
  instance_type = &quot;t3.micro&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;你可以直接从 AWS 管理控制台找到所需的 AMI 和实例类型。为了保持简单和小型,我选择了免费层中可用的最小 EC2 实例。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/e3f2813e08038ba43098bf2ad4f0c7fc.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/27e7772ec4ca76ed14ff9c1bae055b90.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/46903222ec5a158de50d274a6c300cdf.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;尝试应用你的 terraform 更改。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/f9646e1c9c73ff9a96555f3564e4789a.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;如图,我们的 S3 存储桶和 EC2 实例都已部署。&lt;/p&gt;
&lt;h3&gt;销毁资源&lt;/h3&gt;
&lt;p&gt;本文到此结束。为了控制你的 AWS 账单,建议销毁你为测试目的创建的资源。运行 &lt;code&gt;terraform destroy&lt;/code&gt; 以销毁当前状态下通过 terraform 创建的所有资源。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/dfb61e99c917782069278e034b76a09a.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>DeFi借贷协议的崛起：革新金融借贷模式</title><link>https://blog.ithuo.net/posts/rise-of-defi-lending-protocols-revolutionizing-financial-borrowing/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/rise-of-defi-lending-protocols-revolutionizing-financial-borrowing/</guid><pubDate>Sat, 10 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;去中心化金融(DeFi)借贷协议正在彻底改变传统借贷市场,为用户提供了前所未有的金融机会。本文将深入探讨DeFi借贷的发展、主要协议及其创新,以及未来的发展方向。&lt;/p&gt;
&lt;h2&gt;DeFi借贷的爆发式增长&lt;/h2&gt;
&lt;p&gt;自2020年夏天以来,DeFi借贷市场呈现爆发式增长。&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;市场规模的飞跃&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;截至2024年8月,DeFi借贷协议的总锁仓量(TVL)已达到550.5亿美元,相比一年前增长了21.4倍。其中,借贷协议占据了半壁江山,达到289.9亿美元。这一惊人增长凸显了DeFi借贷在加密金融生态中的核心地位。&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;主要协议的表现&lt;/strong&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Aave:作为市场领导者,Aave的TVL达到210亿美元,占据了DeFi借贷市场的38%。&lt;/li&gt;
&lt;li&gt;Compound:紧随其后,Compound的TVL为90亿美元,市场份额约16%。&lt;/li&gt;
&lt;li&gt;MakerDAO:作为稳定币DAI的发行者,MakerDAO在DeFi借贷中扮演着独特角色,其TVL超过80亿美元。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;主要DeFi借贷协议概述&lt;/h2&gt;
&lt;h2&gt;Compound&lt;/h2&gt;
&lt;p&gt;Compound是最大的DeFi借贷平台之一,主要特点包括:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;支持9种代币,包括ETH、USDC、DAI等。&lt;/li&gt;
&lt;li&gt;采用算法动态调整利率,创造了一个高效的货币市场。&lt;/li&gt;
&lt;li&gt;使用cToken代表用户在Compound上的存款。&lt;/li&gt;
&lt;li&gt;借款人可以使用存入的资产作为抵押品进行借贷。&lt;/li&gt;
&lt;li&gt;利率根据供需关系自动调整。&lt;/li&gt;
&lt;li&gt;提供流动性挖矿奖励,用COMP代币激励用户。&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;白皮书: &lt;a href=&quot;https://compound.finance/documents/Compound.Whitepaper.pdf&quot;&gt;https://compound.finance/documents/Compound.Whitepaper.pdf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href=&quot;https://github.com/compound-finance/compound-protocol&quot;&gt;https://github.com/compound-finance/compound-protocol&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Aave&lt;/h2&gt;
&lt;p&gt;Aave是另一个领先的DeFi借贷协议,具有以下特点:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;支持24种资产的借贷。&lt;/li&gt;
&lt;li&gt;创新性地推出了利率转换、抵押品互换和闪电贷款等新功能。&lt;/li&gt;
&lt;li&gt;提供稳定利率和浮动利率两种选择。&lt;/li&gt;
&lt;li&gt;使用aToken代表用户的存款。&lt;/li&gt;
&lt;li&gt;引入了信用委托功能,允许用户将信用额度委托给其他地址。&lt;/li&gt;
&lt;li&gt;支持多链部署,包括以太坊、Polygon、Avalanche等。&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;白皮书: &lt;a href=&quot;https://github.com/aave/aave-protocol/blob/master/docs/Aave_Protocol_Whitepaper_v1_0.pdf&quot;&gt;https://github.com/aave/aave-protocol/blob/master/docs/Aave_Protocol_Whitepaper_v1_0.pdf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href=&quot;https://github.com/aave/aave-protocol&quot;&gt;https://github.com/aave/aave-protocol&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;MakerDAO&lt;/h2&gt;
&lt;p&gt;MakerDAO是最早的DeFi借贷协议之一,主要特点有:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;支持30多种代币作为抵押品铸造DAI稳定币。&lt;/li&gt;
&lt;li&gt;采用去中心化治理模式,MKR持有者可以参与决策。&lt;/li&gt;
&lt;li&gt;使用智能合约自动化管理抵押品和清算过程。&lt;/li&gt;
&lt;li&gt;引入了多抵押品DAI系统,增加了抵押品种类。&lt;/li&gt;
&lt;li&gt;在连接实体资产方面取得突破,完成了首笔以房产为抵押的贷款。&lt;/li&gt;
&lt;li&gt;通过稳定费来调节DAI的供需平衡。&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;白皮书: &lt;a href=&quot;https://makerdao.com/en/whitepaper/&quot;&gt;https://makerdao.com/en/whitepaper/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href=&quot;https://github.com/makerdao&quot;&gt;https://github.com/makerdao&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Cream Finance&lt;/h2&gt;
&lt;p&gt;Cream Finance专注于长尾资产,主要特点包括:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;支持45种抵押品和65种借贷资产。&lt;/li&gt;
&lt;li&gt;推出了Iron Bank无抵押贷款服务,为机构用户提供更多选择。&lt;/li&gt;
&lt;li&gt;采用类似Compound的利率模型。&lt;/li&gt;
&lt;li&gt;提供跨链借贷服务,支持多个区块链网络。&lt;/li&gt;
&lt;li&gt;引入了杠杆代币和固定利率借贷等创新产品。&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;白皮书: &lt;a href=&quot;https://docs.cream.finance/&quot;&gt;https://docs.cream.finance/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href=&quot;https://github.com/CreamFi&quot;&gt;https://github.com/CreamFi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;DeFi借贷的创新与优势&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;无需信用评估,降低了准入门槛&lt;/li&gt;
&lt;li&gt;利用智能合约实现自动化操作,提高效率&lt;/li&gt;
&lt;li&gt;透明度高,所有交易公开可查&lt;/li&gt;
&lt;li&gt;灵活性强,支持多种资产和借贷模式&lt;/li&gt;
&lt;li&gt;利率市场化,由供需决定&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;结语&lt;/h2&gt;
&lt;p&gt;DeFi借贷协议正在重塑金融借贷模式,为用户提供更多元化、更灵活的金融服务。随着技术不断创新和完善,我们可以期待看到DeFi借贷在提高资本效率、连接实体经济等方面取得更多突破,进一步推动金融民主化进程。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>DEX聚合器：DeFi生态系统中的关键创新</title><link>https://blog.ithuo.net/posts/dex-aggregators-key-innovation-defi-ecosystem/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/dex-aggregators-key-innovation-defi-ecosystem/</guid><pubDate>Wed, 07 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;去中心化交易所（DEX）聚合器已成为DeFi生态系统中不可或缺的一部分，为用户提供了更高效、更经济的交易体验。本文将深入探讨DEX聚合器的重要性、主要参与者及其特点。&lt;/p&gt;
&lt;h2&gt;DEX聚合器的重要性&lt;/h2&gt;
&lt;p&gt;在DeFi生态系统中，流动性分散在多个DEX平台上，导致单一DEX的流动性可能不足，尤其是对大额交易而言。DEX聚合器通过汇集多个DEX的流动性，为用户提供以下优势：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;更优惠的价格执行：通过汇集多个DEX的流动性,聚合器能为用户找到最佳价格。&lt;/li&gt;
&lt;li&gt;降低价格滑点：尤其对大额交易而言,聚合器可以显著减少因单一DEX流动性不足导致的价格滑点。&lt;/li&gt;
&lt;li&gt;减少gas成本：通过优化交易路径和分割订单,聚合器可以帮助用户节省gas费用。&lt;/li&gt;
&lt;li&gt;提高资本效率：聚合器整合了分散在不同DEX上的流动性,提高了整体资本利用率。&lt;/li&gt;
&lt;li&gt;一站式交易体验：用户无需在多个DEX之间切换,即可获得最优惠的交易条件。&lt;/li&gt;
&lt;li&gt;价格比较便利：聚合器让用户能轻松比较不同DEX的价格,无需手动查询多个平台。&lt;/li&gt;
&lt;li&gt;增强隐私保护：用户可以直接在区块链网络中完成交易,无需将资产转移至中心化交易所。&lt;/li&gt;
&lt;li&gt;额外安全功能：一些聚合器会提供额外的安全措施和算法,以优化用户交易。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;主要DEX聚合器及其特点&lt;/h2&gt;
&lt;h3&gt;1. 1inch Network&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;支持50多个以太坊流动性来源，以及Binance智能链和Polygon网络&lt;/li&gt;
&lt;li&gt;使用Pathfinder算法寻找最佳交易路径&lt;/li&gt;
&lt;li&gt;拥有两个原生代币：CHI（gas代币）和1INCH（治理代币）&lt;/li&gt;
&lt;li&gt;允许用户通过抵押1INCH获得价差盈余&lt;/li&gt;
&lt;li&gt;提供限价订单功能&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. Matcha (由0x实验室开发)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;利用0x协议和API&lt;/li&gt;
&lt;li&gt;结合链上和链下组件优化交易体验&lt;/li&gt;
&lt;li&gt;自动在多个流动性来源之间分割订单&lt;/li&gt;
&lt;li&gt;将所有正向滑点分享给用户&lt;/li&gt;
&lt;li&gt;支持Binance智能链和Polygon网络&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. ParaSwap&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;使用Hopper路由算法&lt;/li&gt;
&lt;li&gt;实施REDUX gas代币以降低gas成本&lt;/li&gt;
&lt;li&gt;收入来源：第三方集成商费用分成和部分正向滑点&lt;/li&gt;
&lt;li&gt;拥有私人做市商提供的本地流动性池&lt;/li&gt;
&lt;li&gt;支持Binance智能链和Polygon网络&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;DEX聚合器性能影响因素&lt;/h2&gt;
&lt;p&gt;评估DEX聚合器性能时，需考虑以下关键因素：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;路由算法效率&lt;/li&gt;
&lt;li&gt;可用流动性来源数量&lt;/li&gt;
&lt;li&gt;当前市场状况&lt;/li&gt;
&lt;li&gt;交易规模&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;值得注意的是，大额交易通常能从DEX聚合器中获得更多优势，而小额交易可能直接使用单一DEX更为合适。&lt;/p&gt;
&lt;h2&gt;结语&lt;/h2&gt;
&lt;p&gt;DEX聚合器代表了DeFi生态系统中可组合性的典范，通过整合多个DEX的流动性，为用户提供更优质的交易体验。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>深入解析去中心化交易所(DEX)：AMM、流动性池与创新</title><link>https://blog.ithuo.net/posts/deep-dive-into-decentralized-exchanges-amm-liquidity-pools-and-innovation/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/deep-dive-into-decentralized-exchanges-amm-liquidity-pools-and-innovation/</guid><pubDate>Fri, 02 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;去中心化交易所(DEX)在DeFi生态系统中扮演着至关重要的角色。本文将深入探讨DEX的核心概念、主要类型、运作机制以及相关风险。&lt;/p&gt;
&lt;h2&gt;DEX的崛起&lt;/h2&gt;
&lt;p&gt;传统上,中心化交易所(CEX)在加密货币交易中占据主导地位。然而,CEX存在一些固有缺陷,如资产托管风险和提现限制等。2020年至2021年间,DEX迅速发展,交易量呈指数级增长,与CEX的差距不断缩小。&lt;/p&gt;
&lt;h2&gt;DEX的类型&lt;/h2&gt;
&lt;p&gt;DEX主要分为两种类型:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;基于订单簿的DEX:如dYdX、Deversifi等,运作方式类似CEX,但资产由用户自行保管。&lt;/li&gt;
&lt;li&gt;基于流动性池的DEX:如Uniswap、SushiSwap等,利用自动做市商(AMM)算法进行定价。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;自动做市商(AMM)&lt;/h2&gt;
&lt;p&gt;AMM是DeFi领域的重要创新,实现了全天候市场、更高的资本可及性和效率。主要的AMM公式包括:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;恒定乘积:x * y = k (如Uniswap)&lt;/li&gt;
&lt;li&gt;恒定和:x + y = k&lt;/li&gt;
&lt;li&gt;恒定平均值(如Balancer)&lt;/li&gt;
&lt;li&gt;混合曲线(如Curve Finance)&lt;a href=&quot;https://nigdaemon.gitbook.io/how-to-defi-advanced-zhogn-wen-b/di-3-zhang-qu-zhong-xin-hua-jiao-yi-suo&quot;&gt;1&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;主流AMM协议对比&lt;/h2&gt;
&lt;h3&gt;Uniswap&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;最受欢迎的AMM x * y = k&lt;/li&gt;
&lt;li&gt;使用恒定乘积公式&lt;/li&gt;
&lt;li&gt;支持任意ERC-20代币交易对&lt;/li&gt;
&lt;li&gt;Uniswap v3引入了集中流动性和多费率选择&lt;a href=&quot;https://nigdaemon.gitbook.io/how-to-defi-advanced-zhogn-wen-b/di-3-zhang-qu-zhong-xin-hua-jiao-yi-suo&quot;&gt;1&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;SushiSwap&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Uniswap的分叉版本&lt;/li&gt;
&lt;li&gt;引入SUSHI代币激励&lt;/li&gt;
&lt;li&gt;支持多链部署&lt;a href=&quot;https://nigdaemon.gitbook.io/how-to-defi-advanced-zhogn-wen-b/di-3-zhang-qu-zhong-xin-hua-jiao-yi-suo&quot;&gt;1&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Balancer&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;支持多资产池(最多16种资产)&lt;/li&gt;
&lt;li&gt;允许自定义费率和权重&lt;/li&gt;
&lt;li&gt;推出创新的IDO方式:流动性引导池(LBP)&lt;a href=&quot;https://nigdaemon.gitbook.io/how-to-defi-advanced-zhogn-wen-b/di-3-zhang-qu-zhong-xin-hua-jiao-yi-suo&quot;&gt;1&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Curve Finance&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;专注于相似价值资产的互换&lt;/li&gt;
&lt;li&gt;使用混合曲线AMM模型&lt;/li&gt;
&lt;li&gt;支持收益代币和元池&lt;a href=&quot;https://nigdaemon.gitbook.io/how-to-defi-advanced-zhogn-wen-b/di-3-zhang-qu-zhong-xin-hua-jiao-yi-suo&quot;&gt;1&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Bancor&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;最早的AMM之一&lt;/li&gt;
&lt;li&gt;使用BNT作为中间货币&lt;/li&gt;
&lt;li&gt;引入单边质押和无常损失保险&lt;a href=&quot;https://nigdaemon.gitbook.io/how-to-defi-advanced-zhogn-wen-b/di-3-zhang-qu-zhong-xin-hua-jiao-yi-suo&quot;&gt;1&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;AMM的主要区别&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;资金池费用:固定vs可变&lt;/li&gt;
&lt;li&gt;流动性挖矿:激励机制差异&lt;/li&gt;
&lt;li&gt;资金池权重:固定vs可变vs动态&lt;a href=&quot;https://nigdaemon.gitbook.io/how-to-defi-advanced-zhogn-wen-b/di-3-zhang-qu-zhong-xin-hua-jiao-yi-suo&quot;&gt;1&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;使用AMM的风险&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;价格滑点:大额交易可能导致显著滑点&lt;/li&gt;
&lt;li&gt;抢跑:交易可能被套利者抢先执行&lt;/li&gt;
&lt;li&gt;无常损失:为流动性池提供资金可能导致机会成本&lt;a href=&quot;https://nigdaemon.gitbook.io/how-to-defi-advanced-zhogn-wen-b/di-3-zhang-qu-zhong-xin-hua-jiao-yi-suo&quot;&gt;1&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;创新与未来发展&lt;/h2&gt;
&lt;p&gt;DEX领域不断涌现创新,如PancakeSwap(BSC生态)、TerraSwap(Terra生态)和0x协议(DEX基础设施层)等。未来,我们可能会看到更多跨链DEX解决方案、Layer 2扩展方案以及新型AMM模型的出现。&lt;/p&gt;
&lt;h2&gt;结语&lt;/h2&gt;
&lt;p&gt;DEX在推动DeFi发展方面发挥着关键作用,它不仅提供了去中心化的交易环境,还为加密货币定价和流动性提供了重要参考。随着技术不断进步,DEX有望在未来的金融生态系统中占据更加重要的地位。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>DeFi-理解收益耕作、流动性挖矿和IDO</title><link>https://blog.ithuo.net/posts/defi-revolution-understanding-yield-farming-liquidity-mining-and-ido-2/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/defi-revolution-understanding-yield-farming-liquidity-mining-and-ido-2/</guid><pubDate>Mon, 29 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;什么是收益耕作?&lt;/h2&gt;
&lt;p&gt;收益耕作是指用户将加密货币资产存入DeFi协议的流动性池中,以赚取额外收益的过程。这些收益通常以利息、交易费分成或额外代币的形式支付。&lt;/p&gt;
&lt;h3&gt;收益耕作的主要特点:&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;通过提供流动性来赚取收益&lt;/li&gt;
&lt;li&gt;收益率通常以年化收益率(APY)表示&lt;/li&gt;
&lt;li&gt;收益可能远高于传统金融产品&lt;/li&gt;
&lt;li&gt;涉及较高风险,收益率可能波动很大&lt;/li&gt;
&lt;li&gt;需要用户积极管理资产以优化收益&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;收益耕作的工作原理&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;存入资产&lt;/strong&gt;: 用户将加密货币存入特定的DeFi协议或流动性池。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;获得LP代币&lt;/strong&gt;: 作为存入资产的凭证,用户会收到流动性提供者(LP)代币。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;赚取收益&lt;/strong&gt;: 协议会根据用户提供的流动性比例,分配交易费或其他奖励。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;复投或提取&lt;/strong&gt;: 用户可以选择将收益再投资以复利,或者提取收益。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;策略调整&lt;/strong&gt;: 用户可以在不同协议间转移资产,以追求更高收益。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;常见的收益耕作策略&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;流动性提供&lt;/strong&gt;: 在去中心化交易所(DEX)的交易对中提供流动性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;借贷&lt;/strong&gt;: 在DeFi借贷平台上存入资产,赚取利息。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;质押&lt;/strong&gt;: 将代币质押在特定协议中,获得奖励。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;杠杆耕作&lt;/strong&gt;: 借入资产进行更大规模的耕作,以提高潜在收益(但风险也更高)。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;收益耕作的主要风险&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;无常损失&lt;/strong&gt;: 当提供流动性的资产价格发生变化时,可能导致损失。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;智能合约风险&lt;/strong&gt;: 协议中的漏洞可能被黑客利用,导致资金损失。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;市场风险&lt;/strong&gt;: 加密货币市场的高波动性可能导致资产价值大幅下跌。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;流动性风险&lt;/strong&gt;: 某些协议可能设有锁定期,影响资金流动性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;监管风险&lt;/strong&gt;: DeFi领域的监管不确定性可能影响收益耕作活动。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;收益耕作平台&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Aave&lt;/li&gt;
&lt;li&gt;Compound&lt;/li&gt;
&lt;li&gt;Uniswap&lt;/li&gt;
&lt;li&gt;Curve Finance&lt;/li&gt;
&lt;li&gt;PancakeSwap&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;什么是流动性挖矿?&lt;/h2&gt;
&lt;p&gt;流动性挖矿是指用户将加密货币资产存入DeFi协议的流动性池中,以赚取额外收益的过程。这些收益通常以利息、交易费分成或额外代币的形式支付。&lt;/p&gt;
&lt;h3&gt;流动性挖矿的主要特点:&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;通过提供流动性来赚取收益&lt;/li&gt;
&lt;li&gt;收益率通常以年化收益率(APY)表示&lt;/li&gt;
&lt;li&gt;收益可能远高于传统金融产品&lt;/li&gt;
&lt;li&gt;涉及较高风险,收益率可能波动很大&lt;/li&gt;
&lt;li&gt;需要用户积极管理资产以优化收益&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;流动性挖矿的工作原理&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;存入资产&lt;/strong&gt;: 用户将加密货币存入特定的DeFi协议或流动性池。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;获得LP代币&lt;/strong&gt;: 作为存入资产的凭证,用户会收到流动性提供者(LP)代币。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;赚取收益&lt;/strong&gt;: 协议会根据用户提供的流动性比例,分配交易费或其他奖励[1]。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;复投或提取&lt;/strong&gt;: 用户可以选择将收益再投资以复利,或者提取收益。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;策略调整&lt;/strong&gt;: 用户可以在不同协议间转移资产,以追求更高收益。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;常见的流动性挖矿策略&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;流动性提供&lt;/strong&gt;: 在去中心化交易所(DEX)的交易对中提供流动性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;借贷&lt;/strong&gt;: 在DeFi借贷平台上存入资产,赚取利息。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;质押&lt;/strong&gt;: 将代币质押在特定协议中,获得奖励。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;杠杆挖矿&lt;/strong&gt;: 借入资产进行更大规模的挖矿,以提高潜在收益(但风险也更高)。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;流动性挖矿的主要风险&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;无常损失&lt;/strong&gt;: 当提供流动性的资产价格发生变化时,可能导致损失。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;智能合约风险&lt;/strong&gt;: 协议中的漏洞可能被黑客利用,导致资金损失。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;市场风险&lt;/strong&gt;: 加密货币市场的高波动性可能导致资产价值大幅下跌。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;流动性风险&lt;/strong&gt;: 某些协议可能设有锁定期,影响资金流动性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;监管风险&lt;/strong&gt;: DeFi领域的监管不确定性可能影响流动性挖矿活动。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;什么是IDO?&lt;/h2&gt;
&lt;p&gt;IDO全称为Initial DEX Offering(首次去中心化交易所发行),是一种在去中心化交易所(DEX)上进行的代币发行和融资方式。它允许加密货币项目直接在DEX上发行和销售其代币,为项目筹集资金。&lt;/p&gt;
&lt;h3&gt;IDO的主要特点:&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;去中心化: 在DEX上进行,无需中心化交易所审核&lt;/li&gt;
&lt;li&gt;即时流动性: 代币发行后可立即交易&lt;/li&gt;
&lt;li&gt;成本低: 无需支付高额上币费用&lt;/li&gt;
&lt;li&gt;公平性: 所有投资者有平等参与机会&lt;/li&gt;
&lt;li&gt;快速: 发行过程简单快捷&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;IDO的运作方式&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;项目方在DEX上创建流动性池&lt;/li&gt;
&lt;li&gt;设定初始代币价格和销售数量&lt;/li&gt;
&lt;li&gt;投资者使用主流加密货币(如ETH)购买新代币&lt;/li&gt;
&lt;li&gt;代币发行完成后即可在DEX上自由交易&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;IDO与其他融资方式的比较&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;融资方式&lt;/th&gt;
&lt;th&gt;特点&lt;/th&gt;
&lt;th&gt;优势&lt;/th&gt;
&lt;th&gt;劣势&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;IDO&lt;/td&gt;
&lt;td&gt;在DEX上发行&lt;/td&gt;
&lt;td&gt;即时流动性,成本低&lt;/td&gt;
&lt;td&gt;可能出现价格波动大&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ICO&lt;/td&gt;
&lt;td&gt;项目方直接发行&lt;/td&gt;
&lt;td&gt;筹资金额大&lt;/td&gt;
&lt;td&gt;监管风险高&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IEO&lt;/td&gt;
&lt;td&gt;中心化交易所发行&lt;/td&gt;
&lt;td&gt;有交易所背书&lt;/td&gt;
&lt;td&gt;上币成本高&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;IDO的优势&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;为小型项目提供融资机会&lt;/li&gt;
&lt;li&gt;降低了项目方的融资成本&lt;/li&gt;
&lt;li&gt;为投资者提供更公平的参与机会&lt;/li&gt;
&lt;li&gt;提高了代币的流动性&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;IDO的潜在风险&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;价格波动: 初期可能出现剧烈波动&lt;/li&gt;
&lt;li&gt;项目质量: 门槛低,可能出现低质量项目&lt;/li&gt;
&lt;li&gt;技术风险: 智能合约可能存在漏洞&lt;/li&gt;
&lt;li&gt;监管不确定性: 监管政策尚不明确&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;如何参与IDO&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;准备好支持的钱包(如Rabby Wallet)&lt;/li&gt;
&lt;li&gt;在相关DEX平台注册账户&lt;/li&gt;
&lt;li&gt;准备足够的主流加密货币(如ETH)&lt;/li&gt;
&lt;li&gt;关注项目方公告,了解IDO详情&lt;/li&gt;
&lt;li&gt;在指定时间参与代币购买&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><author>Derick</author></item><item><title>DeFi(去中心化金融)-1</title><link>https://blog.ithuo.net/posts/defi-1-decentralized-finance/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/defi-1-decentralized-finance/</guid><pubDate>Sat, 27 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;:::note
今天开始重新学习DeFi协议，下面是听课和检索资料产生的学习笔记
:::&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;IntensiveCoLearning/DeFi&quot;}&lt;/p&gt;
&lt;h1&gt;什么是DeFi&lt;/h1&gt;
&lt;p&gt;DeFi，全称Decentralized Finance（去中心化金融），是指通过区块链技术实现的一系列金融应用和服务，这些服务绕过了传统的中心化金融机构，如银行、证券公司或支付平台。DeFi的目标是通过智能合约和去中心化网络，提供更安全、透明和可访问的金融服务。&lt;/p&gt;
&lt;p&gt;随着区块链技术的发展和普及，DeFi作为一个新兴的金融领域，正在不断演变和成熟。它不仅提供了更多的金融自由和可能性，也带来了对传统金融体系的深刻反思和重新构想。然而，与此同时，DeFi也面临着诸多挑战，包括技术安全性、监管合规性以及市场接受度等。&lt;/p&gt;
&lt;h1&gt;DeFi的核心特点&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;去中心化&lt;/strong&gt;：DeFi应用运行在分布式的区块链网络上，没有单点故障，也不依赖于任何中心化的机构或个体。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;透明性&lt;/strong&gt;：所有的交易和智能合约的执行都是公开可见的，这增加了系统的透明度和可信度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不可篡改性&lt;/strong&gt;：一旦交易被记录在区块链上，就几乎无法被篡改或删除，这保证了数据的真实性和完整性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;智能合约&lt;/strong&gt;：DeFi应用大量使用智能合约来自动执行预设的规则和条件，无需人为干预。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;互操作性&lt;/strong&gt;：不同的DeFi应用可以通过标准化的协议和代币进行交互，创建更复杂的金融服务和产品。&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;DeFi在区块链技术中的应用和影响&lt;/h1&gt;
&lt;h2&gt;应用&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;借贷平台&lt;/strong&gt;：通过智能合约和去中心化的资产托管，用户可以在DeFi平台上进行借贷，无需传统金融机构的介入。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;去中心化交易所（DEX）&lt;/strong&gt;：允许用户直接在区块链上进行代币交易，无需中心化的交易撮合。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支付和汇款&lt;/strong&gt;：通过区块链的跨境支付和汇款服务，可以大大降低交易成本和时间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;预测市场&lt;/strong&gt;：利用智能合约创建基于各种事件结果的预测市场。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;合成资产和衍生品&lt;/strong&gt;：通过智能合约模拟传统金融资产的行为，创建合成资产和衍生品。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;影响&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;对传统金融的挑战&lt;/strong&gt;：DeFi提供了一种全新的金融服务模式，可能会对传统金融机构构成挑战。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;金融包容性&lt;/strong&gt;：降低了金融服务的门槛，使得更多人能够访问和使用金融服务。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;创新驱动&lt;/strong&gt;：DeFi的快速发展推动了区块链技术和智能合约的创新和应用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;监管挑战&lt;/strong&gt;：DeFi的去中心化和跨境特性给监管机构带来了新的挑战。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;安全性问题&lt;/strong&gt;：虽然区块链本身被认为是安全的，但DeFi应用仍然可能受到智能合约漏洞、钓鱼攻击等安全威胁。&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;DeFi借贷&lt;/h1&gt;
&lt;p&gt;DeFi借贷是指通过区块链技术实现的去中心化金融借贷。它将传统金融中的中介机构（如银行或其他金融机构）去除，从而实现了用户之间的直接交易。在DeFi借贷中，用户可以将自己的数字资产作为抵押品，向其他用户借款，同时也可以将自己的数字资产提供给借款人，从中获取借款利息。&lt;/p&gt;
&lt;p&gt;这种借贷方式的核心是利用区块链技术和智能合约来促进和保障交易的进行。智能合约被用来在借款人和贷款人之间建立和执行交易条款，从而消除了对中心化中介机构的需求。通过这种方式，DeFi借贷能够为用户提供更高效、透明和安全的金融服务。&lt;/p&gt;
&lt;p&gt;一些最受欢迎的DeFi借贷平台包括：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;MakerDAO&lt;/code&gt;：MakerDAO是DeFi领域最为著名的借贷平台之一。用户可以将ETH等数字资产抵押在MakerDAO上，然后借出其稳定币Dai进行交易或其他用途。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Compound&lt;/code&gt;：Compound同样是一个基于以太坊的抵押借贷平台，用户可以通过抵押一种代币借出另一种代币。此外，Compound还允许用户将代币存入资金池中以赚取利息。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Aave&lt;/code&gt;：Aave提供了去中心化的借贷服务，但与其他平台略有不同。它的闪贷功能主要面向套利交易者而非传统借款人。&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;去中心化交易所&lt;/h1&gt;
&lt;p&gt;去中心化交易所（&lt;code&gt;DEX&lt;/code&gt;, &lt;code&gt;Decentralized Exchange&lt;/code&gt;）是一个基于区块链技术的交易平台，它不依赖于中心化的机构或个体进行运营和管理。与传统的中心化交易所不同，&lt;code&gt;DEX&lt;/code&gt; 通过智能合约和分布式账本来执行交易，从而实现了去中心化、透明性和安全性。&lt;/p&gt;
&lt;p&gt;在DEX上进行交易时，用户可以直接与其他用户进行点对点的交易，无需通过中心化的交易所或中介机构。这种交易方式消除了单点故障和中心化风险，同时也提高了交易的隐私性和匿名性。因为所有的交易记录都存储在区块链上，所以交易数据具有不可篡改性和可追溯性。&lt;/p&gt;
&lt;p&gt;DEX通常使用自动做市商（&lt;code&gt;AMM&lt;/code&gt;）模型和流动性池来提供流动性，使得交易可以更加快速和便捷地完成。此外，DEX还支持各种不同类型的代币交易，包括加密货币、稳定币、合成资产等。&lt;/p&gt;
&lt;h1&gt;发展历史&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DEX 1.0&lt;/code&gt;是去中心化交易所的初级阶段，它的主要特点是实现了基本的去中心化交易功能，允许用户在没有中心化机构干预的情况下进行点对点的资产交易。这一阶段的DEX通常关注于提供基本的交易服务，如订单簿、撮合引擎等，并努力在交易速度、用户体验和安全性方面达到要求。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然而，&lt;code&gt;DEX 1.0&lt;/code&gt;在流动性和用户体验方面往往面临挑战。由于去中心化的特性，&lt;code&gt;DEX 1.0&lt;/code&gt;通常难以吸引足够的流动性提供者，导致交易对的价格波动较大，交易深度不足。此外，交易速度和用户体验也可能受到区块链性能的限制。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DEX 2.0&lt;/code&gt;是在&lt;code&gt;DEX 1.0&lt;/code&gt;的基础上进行了显著的改进和创新。它更加注重打造一个综合性的去中心化金融平台，而不仅仅是一个简单的交易所。&lt;code&gt;DEX 2.0&lt;/code&gt;通过引入更复杂的金融产品和服务，如流动性挖矿、去中心化借贷、合成资产等，以及优化交易机制和用户界面，来提供更好的流动性和用户体验。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此外，&lt;code&gt;DEX 2.0&lt;/code&gt;还致力于通过激励机制和社区治理来推动去中心化金融生态的发展。它通过流动性激励、交易手续费返还等方式吸引更多的用户参与交易和提供流动性。同时&lt;code&gt;DEX 2.0&lt;/code&gt;也积极探索社区治理机制，将决策权交给社区成员，以实现更加民主和透明的治理方式。&lt;/p&gt;
&lt;p&gt;总的来说，&lt;code&gt;DEX 2.0&lt;/code&gt;在功能特点、流动性和用户体验以及对DeFi生态的贡献方面都超越了&lt;code&gt;DEX 1.0&lt;/code&gt;，代表了去中心化交易所向更加成熟和多元化的发展方向迈进。&lt;/p&gt;
&lt;h1&gt;什么是流动性挖矿&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;流动性挖矿&lt;/code&gt;（&lt;strong&gt;Yield Farming&lt;/strong&gt;）是一种&lt;code&gt;DeFi&lt;/code&gt;（去中心化金融）投资策略，用户通过向DeFi协议提供资产的流动性，以获取收益。简单来说，就是用户将他们的加密货币资产存入去中心化交易所的资金池中，为交易对提供流动性，从而赚取交易手续费、治理代币等奖励。&lt;/p&gt;
&lt;p&gt;流动性挖矿的收益可以来源于多个方面，例如交易手续费、平台币奖励等。交易手续费是交易者在交易所进行交易时需要支付的费用，而这部分费用会按照一定比例分配给提供流动性的用户。平台币奖励则是某些去中心化交易所为了吸引用户提供流动性而发放的一种奖励，通常以该交易所的平台币形式发放。&lt;/p&gt;
&lt;p&gt;流动性挖矿的内在逻辑在于，通过吸引用户向资金池提供流动性，从而快速扩大资金池的规模，增加交易对的流动性，降低交易滑点，提高交易效率。同时，用户也能通过提供流动性获得收益，实现资产增值。&lt;/p&gt;
&lt;h3&gt;以下是一些知名的去中心化交易所：&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Uniswap&lt;/code&gt;：&lt;a href=&quot;https://uniswap.org/&quot;&gt;Uniswap&lt;/a&gt;是目前最大的去中心化交易所之一，部署在以太坊上，采用自动做市商（AMM）模式提供流动性。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Sushiswap&lt;/code&gt;：&lt;a href=&quot;https://www.sushi.com/swap&quot;&gt;Sushiswap&lt;/a&gt;是另一个基于以太坊的去中心化交易所，与Uniswap类似，但提供了一些额外的功能和激励措施。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PancakeSwap&lt;/code&gt;：&lt;a href=&quot;https://pancakeswap.finance/&quot;&gt;PancakeSwap&lt;/a&gt;是部署在币安智能链（BSC）上的去中心化交易所，提供快速的交易速度和低手续费。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Curve Finance&lt;/code&gt;：&lt;a href=&quot;https://curve.fi/#/ethereum/swap?from=0xdac17f958d2ee523a2206206994597c13d831ec7&amp;amp;to=0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee&quot;&gt;Curve Finance&lt;/a&gt;专注于稳定币和类似资产的交易，提供低滑点和低手续费的交易体验。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Balancer&lt;/code&gt;：&lt;a href=&quot;https://balancer.fi/&quot;&gt;Balancer&lt;/a&gt;是一个可编程的流动性提供平台，允许用户创建自定义的流动性池和交易策略。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Q老师推荐的一些常用的DeFi资讯工具&lt;/h3&gt;
&lt;h3&gt;&lt;strong&gt;Debank&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Debank&lt;/strong&gt; 是一个多链资产管理平台，旨在为用户提供一个统一的界面来管理他们在不同区块链上的数字资产。它可以帮助用户追踪他们的资产、交易历史、NFT 收藏以及 DeFi 协议的参与情况。Debank 的主要功能包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;多链支持：&lt;/strong&gt; 支持包括以太坊、BSC、Polygon 等在内的多个主流区块链。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;资产追踪：&lt;/strong&gt; 实时跟踪用户在不同钱包和交易所的资产。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;交易历史查询：&lt;/strong&gt; 提供详细的交易记录和分析。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NFT 收藏展示：&lt;/strong&gt; 展示用户所拥有的 NFT 作品。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DeFi 协议数据：&lt;/strong&gt; 提供 DeFi 协议的收益、风险等数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;官方网站：&lt;/strong&gt; &lt;a href=&quot;https://debank.com/&quot;&gt;https://debank.com/&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Foresight News&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Foresight News&lt;/strong&gt; 是一个专注于区块链和加密货币领域的新闻媒体。它提供最新的行业资讯、技术分析、项目报道以及市场动态。Foresight News 的内容涵盖了区块链技术、DeFi、NFT、元宇宙等多个方面。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;官方网站：&lt;/strong&gt; &lt;a href=&quot;https://foresightnews.pro/&quot;&gt;FN精选 - Foresight News&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Chainfeeds.xyz&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Chainfeeds.xyz&lt;/strong&gt; 是一个区块链数据聚合平台。它通过 API 接口的方式为开发者提供链上数据的访问服务。开发者可以使用 Chainfeeds.xyz 的 API 来构建自己的去中心化应用程序 (dApp) 或数据分析工具。Chainfeeds.xyz 支持多个区块链，并提供丰富的数据类型，包括交易、区块、智能合约、NFT 等。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;官方网站：&lt;/strong&gt; &lt;a href=&quot;https://chainfeeds.xyz/&quot;&gt;https://chainfeeds.xyz/&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;目前最好用的浏览器钱包&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;What is Rabby Wallet?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Rabby Wallet is an open-source crypto wallet that functions as a browser extension. It&apos;s designed with Decentralized Finance (&lt;code&gt;DeFi&lt;/code&gt;) users in mind and offers several features to make interacting with DeFi applications (&lt;code&gt;dApps&lt;/code&gt;) smoother and potentially safer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key Features:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Multi-chain support:&lt;/strong&gt; Works with Ethereum and other blockchains compatible with the Ethereum Virtual Machine (&lt;code&gt;EVM&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security focus:&lt;/strong&gt; Includes a built-in security rule engine to scan transactions for potential risks before you sign them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Seamless dApp connection:&lt;/strong&gt; Automatically switches to the appropriate blockchain network based on the dApp you&apos;re using.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Portfolio tracking:&lt;/strong&gt; Tracks all your holdings across supported blockchains in one place.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mobile app:&lt;/strong&gt; Available for Android devices (iOS availability might be limited depending on region).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Official Website:&lt;/strong&gt; &lt;a href=&quot;https://rabby.io/&quot;&gt;https://rabby.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Google Play Store:&lt;/strong&gt; &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.debank.rabbymobile&amp;amp;hl=en_US&quot;&gt;https://play.google.com/store/apps/details?id=com.debank.rabbymobile&amp;amp;hl=en_US&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Derick</author></item><item><title>基于OP Stack搭建L2公链</title><link>https://blog.ithuo.net/posts/building-l2-blockchain-based-on-op-stack/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/building-l2-blockchain-based-on-op-stack/</guid><pubDate>Mon, 22 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;使用&lt;strong&gt;OP Stack&lt;/strong&gt;从零开始搭建 L2 Rollup&lt;/h1&gt;
&lt;p&gt;:::info
请&lt;strong&gt;预留大约一个小时&lt;/strong&gt;来确保一切正常运行，并&lt;strong&gt;仔细阅读本指南&lt;/strong&gt;。
你不会想错过任何可能导致后续问题的步骤。
:::&lt;/p&gt;
&lt;p&gt;本教程是&lt;strong&gt;为希望通过启动 OP Stack 测试网链来了解 OP Stack 的开发人员设计的&lt;/strong&gt;。通过本文你将了解完整的部署过程，并学习构成 OP Stack 的所有组件，&lt;strong&gt;最终你将拥有自己的 OP Stack 测试网&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;软件依赖&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;依赖&lt;/th&gt;
&lt;th&gt;版本&lt;/th&gt;
&lt;th&gt;版本检查命令&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://git-scm.com/&quot;&gt;git&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;^2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git --version&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://go.dev/&quot;&gt;go&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;^1.21&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;go version&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://nodejs.org/en/&quot;&gt;node&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;^20&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;node --version&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://pnpm.io/installation&quot;&gt;pnpm&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;^8&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pnpm --version&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/foundry-rs/foundry#installation&quot;&gt;foundry&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;^0.2.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;forge --version&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://linux.die.net/man/1/make&quot;&gt;make&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;^3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;make --version&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/jqlang/jq&quot;&gt;jq&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;^1.6&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;jq --version&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://direnv.net&quot;&gt;direnv&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;^2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;direnv --version&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;关于特定依赖的说明&lt;/h3&gt;
&lt;h4&gt;&lt;code&gt;node&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;我们建议使用最新 LTS 版本的 Node.js（当前为 v20）。
&lt;a href=&quot;https://github.com/nvm-sh/nvm&quot;&gt;&lt;code&gt;nvm&lt;/code&gt;&lt;/a&gt; 是一个有用的工具，可以帮助你管理机器上的多个 Node.js 版本。&lt;/p&gt;
&lt;h4&gt;&lt;code&gt;foundry&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;建议使用 monorepo 的 &lt;code&gt;package.json&lt;/code&gt; 中的脚本来管理 &lt;code&gt;foundry&lt;/code&gt;，以确保你始终使用正确的版本。这种方法简化了安装、更新和版本检查过程。在继续之前，请确保在本地克隆 monorepo。&lt;/p&gt;
&lt;h4&gt;&lt;code&gt;direnv&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;本教程的某些部分使用 &lt;a href=&quot;https://direnv.net&quot;&gt;&lt;code&gt;direnv&lt;/code&gt;&lt;/a&gt; 作为一种将环境变量从 &lt;code&gt;.envrc&lt;/code&gt; 文件加载到你的 shell 中的方法。
这意味着你无需每次想使用环境变量时都手动导出它们。
&lt;code&gt;direnv&lt;/code&gt; 只能访问你明确允许它查看的文件。&lt;/p&gt;
&lt;p&gt;在&lt;a href=&quot;https://direnv.net/docs/installation.html&quot;&gt;安装 &lt;code&gt;direnv&lt;/code&gt;&lt;/a&gt;之后，你需要&lt;strong&gt;确保 &lt;a href=&quot;https://direnv.net/docs/hook.html&quot;&gt;&lt;code&gt;direnv&lt;/code&gt; 已连接到你的 shell&lt;/a&gt;&lt;/strong&gt;。
请确保你已按照&lt;a href=&quot;https://direnv.net/docs/hook.html&quot;&gt; &lt;code&gt;direnv&lt;/code&gt; 网站上的指南&lt;/a&gt;进行操作，然后&lt;strong&gt;关闭你的终端并重新打开它&lt;/strong&gt;，以便更改生效（或者如果你知道如何操作，则 &lt;code&gt;source&lt;/code&gt; 你的配置文件）。&lt;/p&gt;
&lt;p&gt;:::tip
请确保你已通过修改你的 shell 配置文件（如 &lt;code&gt;~/.bashrc&lt;/code&gt; 或 &lt;code&gt;~/.zshrc&lt;/code&gt;）将 &lt;code&gt;direnv&lt;/code&gt; 正确连接到你的 shell。
如果你没有编辑配置文件，那么你可能没有正确配置 &lt;code&gt;direnv&lt;/code&gt;（并且稍后可能会出现问题）。
:::&lt;/p&gt;
&lt;h2&gt;获取 Sepolia 节点访问权限&lt;/h2&gt;
&lt;p&gt;跟随本教程将部署一个 OP Stack Rollup 链，该链使用 Layer 1 区块链来托管和排序交易数据。
OP Stack Rollups 被设计为使用 EVM 等效区块链，如 Ethereum、OP Mainnet 或标准 Ethereum 测试网作为其 L1 链。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;本指南使用 Sepolia 测试网作为 L1 链&lt;/strong&gt;。
我们建议你也使用 Sepolia。
你也可以使用其他 EVM 兼容的区块链，但你可能会遇到意外的错误。
如果你想使用其他网络，请务必仔细检查每个命令，并将任何特定于 Sepolia 的值替换为你网络的值。&lt;/p&gt;
&lt;p&gt;由于你正在将 OP Stack 链部署到 Sepolia，因此你需要有权访问 Sepolia 节点。
你可以使用 &lt;a href=&quot;https://www.alchemy.com/&quot;&gt;Alchemy&lt;/a&gt; 等节点提供商（更容易），或者运行你自己的 Sepolia 节点（更难）。&lt;/p&gt;
&lt;h2&gt;构建源代码&lt;/h2&gt;
&lt;p&gt;你将直接从源代码启动你的 OP Stack 链，而不是使用像 &lt;a href=&quot;https://www.docker.com/&quot;&gt;Docker&lt;/a&gt; 这样的容器系统。
虽然这增加了一些额外的步骤，但这意味着如果你想修改堆栈的行为，你将更容易做到。
如果你想要你将使用的各种组件的摘要，请再次查看上面的&lt;a href=&quot;#what-youre-going-to-deploy&quot;&gt;你将要部署的内容&lt;/a&gt;部分。&lt;/p&gt;
&lt;p&gt;:::info
为了简单起见，你将使用主目录 &lt;code&gt;~/&lt;/code&gt; 作为本教程的工作目录。
你可以使用你想要的任何目录，但使用主目录将允许你复制/粘贴本指南中的命令。
如果你选择使用其他目录，请确保你在本教程中的命令中使用了正确的目录。
:::&lt;/p&gt;
&lt;h3&gt;构建 Optimism monorepo&lt;/h3&gt;
&lt;p&gt;&amp;lt;Steps&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;克隆 Optimism Monorepo&amp;lt;/h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd ~
git clone https://github.com/ethereum-optimism/optimism.git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;进入 Optimism Monorepo&amp;lt;/h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd optimism
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;检出正确的 分支&amp;lt;/h4&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Callout&amp;gt;
在本教程中，你将使用 Optimism Monorepo 的 &lt;code&gt;tutorials/chain&lt;/code&gt; 分支来部署 OP Stack 测试网链。
这是一个非生产分支，落后于 &lt;code&gt;develop&lt;/code&gt; 分支。
你&lt;strong&gt;绝不&lt;/strong&gt;应该在生产中使用 &lt;code&gt;develop&lt;/code&gt; 或 &lt;code&gt;tutorials/chain&lt;/code&gt; 分支。
&amp;lt;/Callout&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git checkout tutorials/chain
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;检查你的依赖&amp;lt;/h4&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Callout&amp;gt;
不要跳过此步骤！请确保在继续之前安装了所有必需的依赖项。
&amp;lt;/Callout&amp;gt;&lt;/p&gt;
&lt;p&gt;运行以下脚本并仔细检查你是否安装了所有必需的版本。
如果你没有安装正确的版本，你可能会遇到意外的错误。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./packages/contracts-bedrock/scripts/getting-started/versions.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;安装依赖&amp;lt;/h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pnpm install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;构建 Optimism Monorepo 中的各种包&amp;lt;/h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;make op-node op-batcher op-proposer
pnpm build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Steps&amp;gt;&lt;/p&gt;
&lt;h3&gt;构建 &lt;code&gt;op-geth&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&amp;lt;Steps&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;克隆 op-geth&amp;lt;/h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd ~
git clone https://github.com/ethereum-optimism/op-geth.git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;进入 op-geth&amp;lt;/h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd op-geth
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;构建 op-geth&amp;lt;/h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;make geth
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Steps&amp;gt;&lt;/p&gt;
&lt;h2&gt;填写环境变量&lt;/h2&gt;
&lt;p&gt;在开始部署你的链之前，你需要填写一些环境变量。&lt;/p&gt;
&lt;p&gt;&amp;lt;Steps&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;进入 Optimism Monorepo&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd ~/optimism
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;复制示例环境变量文件&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cp .envrc.example .envrc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;填写环境变量文件&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;打开环境变量文件并填写以下变量：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;变量名&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;L1_RPC_URL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;你的 L1 节点的 URL（在本例中为 Sepolia 节点）。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;L1_RPC_KIND&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;你正在连接的 L1 RPC 的类型，用于通知最佳交易收据获取。有效选项：&lt;code&gt;alchemy&lt;/code&gt;、&lt;code&gt;quicknode&lt;/code&gt;、&lt;code&gt;infura&lt;/code&gt;、&lt;code&gt;parity&lt;/code&gt;、&lt;code&gt;nethermind&lt;/code&gt;、&lt;code&gt;debug_geth&lt;/code&gt;、&lt;code&gt;erigon&lt;/code&gt;、&lt;code&gt;basic&lt;/code&gt;、&lt;code&gt;any&lt;/code&gt;。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;lt;/Steps&amp;gt;&lt;/p&gt;
&lt;h2&gt;生成地址&lt;/h2&gt;
&lt;p&gt;在设置链时，你需要四个地址及其私钥：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Admin&lt;/code&gt; 地址具有升级合约的能力。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Batcher&lt;/code&gt; 地址将 Sequencer 交易数据发布到 L1。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Proposer&lt;/code&gt; 地址将 L2 交易结果（状态根）发布到 L1。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Sequencer&lt;/code&gt; 地址在 p2p 网络上签署区块。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;Steps&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;进入 Optimism Monorepo&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd ~/optimism
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;生成新地址&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;:::caution
你&lt;strong&gt;不&lt;/strong&gt;应该将 &lt;code&gt;wallets.sh&lt;/code&gt; 工具用于生产部署。
如果你要将基于 OP Stack 的链部署到生产环境中，你应该使用硬件安全模块和硬件钱包的组合。
:::&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./packages/contracts-bedrock/scripts/getting-started/wallets.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;检查输出&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;确保你看到的输出类似于以下内容：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;将以下内容复制到你的 .envrc 文件中：

# Admin 地址
export GS_ADMIN_ADDRESS=0x9625B9aF7C42b4Ab7f2C437dbc4ee749d52E19FC
export GS_ADMIN_PRIVATE_KEY=0xbb93a75f64c57c6f464fd259ea37c2d4694110df57b2e293db8226a502b30a34

# Batcher 地址
export GS_BATCHER_ADDRESS=0xa1AEF4C07AB21E39c37F05466b872094edcf9cB1
export GS_BATCHER_PRIVATE_KEY=0xe4d9cd91a3e53853b7ea0dad275efdb5173666720b1100866fb2d89757ca9c5a

# Proposer 地址
export GS_PROPOSER_ADDRESS=0x40E805e252D0Ee3D587b68736544dEfB419F351b
export GS_PROPOSER_PRIVATE_KEY=0x2d1f265683ebe37d960c67df03a378f79a7859038c6d634a61e40776d561f8a2

# Sequencer 地址
export GS_SEQUENCER_ADDRESS=0xC06566E8Ec6cF81B4B26376880dB620d83d50Dfb
export GS_SEQUENCER_PRIVATE_KEY=0x2a0290473f3838dbd083a5e17783e3cc33c905539c0121f9c76614dda8a38dca
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;保存地址&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;将上一步的输出复制并粘贴到你的 &lt;code&gt;.envrc&lt;/code&gt; 文件中，如指示。&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;为地址提供资金&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;你需要向 &lt;code&gt;Admin&lt;/code&gt;、&lt;code&gt;Proposer&lt;/code&gt; 和 &lt;code&gt;Batcher&lt;/code&gt; 地址发送 ETH。&lt;/strong&gt;
所需的 ETH 确切数量取决于所使用的 L1 网络。
&lt;strong&gt;你无需向 &lt;code&gt;Sequencer&lt;/code&gt; 地址发送任何 ETH，因为它不发送交易。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;建议在使用 Sepolia 时使用以下金额为地址提供资金：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Admin&lt;/code&gt; — 0.5 Sepolia ETH&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Proposer&lt;/code&gt; — 0.2 Sepolia ETH&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Batcher&lt;/code&gt; — 0.1 Sepolia ETH&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;要获取为地址提供资金所需的 Sepolia ETH，我们建议使用 &lt;a href=&quot;https://console.optimism.io/faucet?utm_source=docs&quot;&gt;Superchain Faucet&lt;/a&gt; 以及 &lt;a href=&quot;https://help.coinbase.com/en/coinbase/getting-started/getting-started-with-coinbase/id-doc-verification&quot;&gt;Coinbase 验证&lt;/a&gt;。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/Steps&amp;gt;&lt;/p&gt;
&lt;h2&gt;加载环境变量&lt;/h2&gt;
&lt;p&gt;现在你已经填写了环境变量文件，你需要将这些变量加载到你的终端中。&lt;/p&gt;
&lt;p&gt;&amp;lt;Steps&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;进入 Optimism Monorepo&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd ~/optimism
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;使用 direnv 加载变量&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;:::tip
你即将使用 &lt;code&gt;direnv&lt;/code&gt; 将环境变量从 &lt;code&gt;.envrc&lt;/code&gt; 文件加载到你的终端中。
请确保你已&lt;a href=&quot;https://direnv.net/docs/installation.html&quot;&gt;安装 &lt;code&gt;direnv&lt;/code&gt;&lt;/a&gt;并且已将 &lt;code&gt;direnv&lt;/code&gt; 正确&lt;a href=&quot;#configuring-direnv&quot;&gt;连接到你的 shell&lt;/a&gt;。
:::&lt;/p&gt;
&lt;p&gt;接下来，你需要允许 &lt;code&gt;direnv&lt;/code&gt; 读取此文件并将变量加载到你的终端中，使用以下命令。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;direnv allow
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:::tip
警告：每当你的 &lt;code&gt;.envrc&lt;/code&gt; 文件更改时，&lt;code&gt;direnv&lt;/code&gt; 都会卸载自身。
&lt;strong&gt;每次更改 &lt;code&gt;.envrc&lt;/code&gt; 文件时，你&lt;em&gt;必须&lt;/em&gt;重新运行以下命令。&lt;/strong&gt;
:::&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;确认变量已加载&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;运行 &lt;code&gt;direnv allow&lt;/code&gt; 后，你应该看到类似于以下内容的输出（确切的输出将因你设置的变量而异，如果它看起来不完全像这样，请不要担心）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;direnv: loading ~/optimism/.envrc
direnv: export +DEPLOYMENT_CONTEXT +ETHERSCAN_API_KEY +GS_ADMIN_ADDRESS +GS_ADMIN_PRIVATE_KEY +GS_BATCHER_ADDRESS +GS_BATCHER_PRIVATE_KEY +GS_PROPOSER_ADDRESS +GS_PROPOSER_PRIVATE_KEY +GS_SEQUENCER_ADDRESS +GS_SEQUENCER_PRIVATE_KEY +IMPL_SALT +L1_RPC_KIND +L1_RPC_URL +PRIVATE_KEY +TENDERLY_PROJECT +TENDERLY_USERNAME
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;如果你没有看到此输出，则你可能没有&lt;a href=&quot;#configuring-direnv&quot;&gt;正确配置 &lt;code&gt;direnv&lt;/code&gt;&lt;/a&gt;。&lt;/strong&gt;
请确保你已正确配置 &lt;code&gt;direnv&lt;/code&gt; 并再次运行 &lt;code&gt;direnv allow&lt;/code&gt;，以便你看到所需的输出。&lt;/p&gt;
&lt;p&gt;&amp;lt;/Steps&amp;gt;&lt;/p&gt;
&lt;h2&gt;配置你的网络&lt;/h2&gt;
&lt;p&gt;构建完两个存储库后，你需要返回 Optimism Monorepo 以设置你的链的配置文件。
目前，链配置以 JSON 文件的形式存在于 &lt;a href=&quot;https://github.com/ethereum-optimism/optimism/tree/v1.1.4/packages/contracts-bedrock&quot;&gt;&lt;code&gt;contracts-bedrock&lt;/code&gt;&lt;/a&gt; 包中。&lt;/p&gt;
&lt;p&gt;&amp;lt;Steps&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;进入 Optimism Monorepo&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd ~/optimism
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;移动到 contracts-bedrock 包中&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd packages/contracts-bedrock
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;生成配置文件&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;运行以下脚本以在 &lt;code&gt;deploy-config&lt;/code&gt; 目录中生成 &lt;code&gt;getting-started.json&lt;/code&gt; 配置文件。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./scripts/getting-started/config.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;查看配置文件（可选）&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;如果你愿意，你可以通过在你喜欢的文本编辑器中打开 &lt;code&gt;deploy-config/getting-started.json&lt;/code&gt; 来查看刚刚生成的配置文件。
建议暂时保持此文件原样，这样你就不会遇到任何意外的错误。&lt;/p&gt;
&lt;p&gt;&amp;lt;/Steps&amp;gt;&lt;/p&gt;
&lt;h2&gt;部署 Create2 工厂（可选）&lt;/h2&gt;
&lt;p&gt;如果你要将 OP Stack 链部署到 Sepolia 以外的网络，你可能需要在 L1 链上部署 Create2 工厂合约。
此工厂合约用于以确定性的方式部署 OP Stack 智能合约。&lt;/p&gt;
&lt;p&gt;:::tip
此步骤通常仅在你将 OP Stack 链部署到自定义 L1 链时才需要。
如果你要将 OP Stack 链部署到 Sepolia，则可以安全地跳过此步骤。
:::&lt;/p&gt;
&lt;p&gt;&amp;lt;Steps&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;检查工厂是否存在&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;Create2 工厂合约将部署在地址 &lt;code&gt;0x4e59b44847b379578588920cA78FbF26c0B4956C&lt;/code&gt;。
你可以使用区块浏览器或运行以下命令来检查此合约是否已部署到你的 L1 网络：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cast codesize 0x4e59b44847b379578588920cA78FbF26c0B4956C --rpc-url $L1_RPC_URL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果命令返回 &lt;code&gt;0&lt;/code&gt;，则表示尚未部署该合约。
如果命令返回 &lt;code&gt;69&lt;/code&gt;，则表示已部署该合约，你可以安全地跳过此部分。&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;为工厂部署者提供资金&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;你需要向将用于部署工厂合约的地址 &lt;code&gt;0x3fAB184622Dc19b6109349B94811493BF2a45362&lt;/code&gt; 发送一些 ETH。
此地址只能用于部署工厂合约，不会用于其他任何用途。
在你的 L1 链上向此地址发送至少 1 ETH。&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;部署工厂&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;使用 &lt;code&gt;cast&lt;/code&gt;，将工厂合约部署到你的 L1 链：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cast publish --rpc-url $L1_RPC_URL 0xf8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;等待交易被挖掘&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;请确保交易包含在你的 L1 链上的区块中，然后再继续。&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;验证工厂是否已部署&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;再次运行代码大小检查，以确保工厂已正确部署：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cast codesize 0x4e59b44847b379578588920cA78FbF26c0B4956C --rpc-url $L1_RPC_URL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Steps&amp;gt;&lt;/p&gt;
&lt;h2&gt;部署 L1 合约&lt;/h2&gt;
&lt;p&gt;配置完你的网络后，就可以部署链功能所需的 L1 合约了。&lt;/p&gt;
&lt;p&gt;&amp;lt;Steps&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;部署 L1 合约&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;forge script scripts/Deploy.s.sol:Deploy --private-key $GS_ADMIN_PRIVATE_KEY --broadcast --rpc-url $L1_RPC_URL --slow
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:::info
如果你看到一个不明确的错误，其中包含 &lt;code&gt;EvmError: Revert&lt;/code&gt; 和 &lt;code&gt;Script failed&lt;/code&gt;，那么你可能需要更改 &lt;code&gt;IMPL_SALT&lt;/code&gt; 环境变量。
此变量确定通过 &lt;a href=&quot;https://eips.ethereum.org/EIPS/eip-1014&quot;&gt;CREATE2&lt;/a&gt; 部署的各种智能合约的地址。
如果使用相同的 &lt;code&gt;IMPL_SALT&lt;/code&gt; 两次部署相同的合约，则第二次部署将失败。
&lt;strong&gt;你可以通过在 Optimism Monorepo 中的任何位置运行 &lt;code&gt;direnv allow&lt;/code&gt; 来生成新的 &lt;code&gt;IMPL_SALT&lt;/code&gt;。&lt;/strong&gt;
:::&lt;/p&gt;
&lt;p&gt;&amp;lt;/Steps&amp;gt;&lt;/p&gt;
&lt;h2&gt;生成 L2 配置文件&lt;/h2&gt;
&lt;p&gt;现在你已经设置了 L1 智能合约，你可以自动生成共识客户端和执行客户端中使用的多个配置文件。&lt;/p&gt;
&lt;p&gt;你需要生成三个重要文件：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;genesis.json&lt;/code&gt; 包括执行客户端的链的创世状态。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rollup.json&lt;/code&gt; 包括共识客户端的配置信息。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jwt.txt&lt;/code&gt; 是一个 &lt;a href=&quot;https://jwt.io/introduction&quot;&gt;JSON Web Token&lt;/a&gt;，允许共识客户端和执行客户端安全地通信（以太坊客户端中使用相同的机制）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;lt;Steps&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;导航到 op-node 包&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd ~/optimism/op-node
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;创建创世文件&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;现在你将在 &lt;code&gt;op-node&lt;/code&gt; 文件夹中生成 &lt;code&gt;genesis.json&lt;/code&gt; 和 &lt;code&gt;rollup.json&lt;/code&gt; 文件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go run cmd/main.go genesis l2 \
  --deploy-config ../packages/contracts-bedrock/deploy-config/getting-started.json \
  --l1-deployments ../packages/contracts-bedrock/deployments/getting-started/.deploy \
  --outfile.l2 genesis.json \
  --outfile.rollup rollup.json \
  --l1-rpc $L1_RPC_URL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;创建身份验证密钥&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;接下来需要创建一个 &lt;a href=&quot;https://jwt.io/introduction&quot;&gt;JSON Web Token&lt;/a&gt;，该令牌将用于验证共识客户端和执行客户端。
此令牌用于确保只有共识客户端和执行客户端才能相互通信。
你可以使用以下命令生成 JWT：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;openssl rand -hex 32 &amp;gt; jwt.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;将创世文件复制到 op-geth 目录中&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;最后需要将 &lt;code&gt;genesis.json&lt;/code&gt; 文件和 &lt;code&gt;jwt.txt&lt;/code&gt; 文件复制到 &lt;code&gt;op-geth&lt;/code&gt; 中，以便你可以使用它来初始化和运行 &lt;code&gt;op-geth&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cp genesis.json ~/op-geth
cp jwt.txt ~/op-geth
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Steps&amp;gt;&lt;/p&gt;
&lt;h2&gt;初始化 &lt;code&gt;op-geth&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;现在只需要运行几个命令来初始化 &lt;code&gt;op-geth&lt;/code&gt; 可以运行你的链了！。
你将运行一个 Sequencer 节点，因此你需要导入你之前生成的 &lt;code&gt;Sequencer&lt;/code&gt; 私钥。
此私钥是你的 Sequencer 将用于签署新区块的密钥。&lt;/p&gt;
&lt;p&gt;&amp;lt;Steps&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;导航到 op-geth 目录&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd ~/op-geth
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;创建数据目录文件夹&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir datadir
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;构建 op-geth 二进制文件&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;make geth
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;初始化 op-geth&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;build/bin/geth init --state.scheme=hash --datadir=datadir genesis.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Steps&amp;gt;&lt;/p&gt;
&lt;h2&gt;启动 &lt;code&gt;op-geth&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;现在你将启动 &lt;code&gt;op-geth&lt;/code&gt;，你的执行客户端。
请注意，在下一步中启动共识客户端之前，你不会看到任何交易。&lt;/p&gt;
&lt;p&gt;&amp;lt;Steps&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;打开一个新的终端&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;你需要一个终端窗口来运行 &lt;code&gt;op-geth&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;导航到 op-geth 目录&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd ~/op-geth
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;运行 op-geth&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;:::info
你在此处使用 &lt;code&gt;--gcmode=archive&lt;/code&gt; 来运行 &lt;code&gt;op-geth&lt;/code&gt;，因为此节点将充当你的 Sequencer。
以存档模式运行 Sequencer 很有用，因为 &lt;code&gt;op-proposer&lt;/code&gt; 需要访问完整状态。
如果你想节省磁盘空间，可以随意以完整模式运行其他（非 Sequencer）节点。只需确保至少存在另一个存档节点，并且 &lt;code&gt;op-proposer&lt;/code&gt; 指向它。
:::&lt;/p&gt;
&lt;p&gt;:::info
重要的是，你此时已按照上一节中的说明初始化了 geth 节点。否则会导致 &lt;code&gt;op-geth&lt;/code&gt; 和 &lt;code&gt;op-node&lt;/code&gt; 之间的启动问题。
:::&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./build/bin/geth \
  --datadir ./datadir \
  --http \
  --http.corsdomain=&quot;*&quot; \
  --http.vhosts=&quot;*&quot; \
  --http.addr=0.0.0.0 \
  --http.api=web3,debug,eth,txpool,net,engine \
  --ws \
  --ws.addr=0.0.0.0 \
  --ws.port=8546 \
  --ws.origins=&quot;*&quot; \
  --ws.api=debug,eth,txpool,net,engine \
  --syncmode=full \
  --gcmode=archive \
  --nodiscover \
  --maxpeers=0 \
  --networkid=42069 \
  --authrpc.vhosts=&quot;*&quot; \
  --authrpc.addr=0.0.0.0 \
  --authrpc.port=8551 \
  --authrpc.jwtsecret=./jwt.txt \
  --rollup.disabletxpoolgossip=true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Steps&amp;gt;&lt;/p&gt;
&lt;h2&gt;启动 &lt;code&gt;op-node&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;如果已经运行了 &lt;code&gt;op-geth&lt;/code&gt;，需要同时运行 &lt;code&gt;op-node&lt;/code&gt;。
与以太坊一样，OP Stack 具有共识客户端 (&lt;code&gt;op-node&lt;/code&gt;) 和执行客户端 (&lt;code&gt;op-geth&lt;/code&gt;)。
共识客户端通过 Engine API “驱动”执行客户端。&lt;/p&gt;
&lt;p&gt;&amp;lt;Steps&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;打开一个新的终端&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;你需要一个终端窗口来运行 &lt;code&gt;op-node&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;导航到 op-node 目录&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd ~/optimism/op-node
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;运行 op-node&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./bin/op-node \
  --l2=http://localhost:8551 \
  --l2.jwt-secret=./jwt.txt \
  --sequencer.enabled \
  --sequencer.l1-confs=5 \
  --verifier.l1-confs=4 \
  --rollup.config=./rollup.json \
  --rpc.addr=0.0.0.0 \
  --p2p.disable \
  --rpc.enable-admin \
  --p2p.sequencer.key=$GS_SEQUENCER_PRIVATE_KEY \
  --l1=$L1_RPC_URL \
  --l1.rpckind=$L1_RPC_KIND
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行此命令后，你应该开始看到 &lt;code&gt;op-node&lt;/code&gt; 开始从 L1 链同步 L2 区块。
一旦 &lt;code&gt;op-node&lt;/code&gt; 赶上 L1 链的顶端，它将开始向 &lt;code&gt;op-geth&lt;/code&gt; 发送区块以供执行。
届时，你将开始看到在 &lt;code&gt;op-geth&lt;/code&gt; 内部创建的区块。&lt;/p&gt;
&lt;p&gt;:::info
&lt;strong&gt;默认情况下，你的 &lt;code&gt;op-node&lt;/code&gt; 将尝试使用对等网络来加速同步过程。&lt;/strong&gt;
如果你使用的链 ID 也被其他人使用，例如本教程的默认链 ID (42069)，你的 &lt;code&gt;op-node&lt;/code&gt; 将收到其他排序器签署的区块。
这些请求将失败并浪费时间和网络资源。
&lt;strong&gt;为了避免这种情况，本教程从禁用对等网络同步开始 (&lt;code&gt;--p2p.disable&lt;/code&gt;)。&lt;/strong&gt;
:::
一旦你有多个节点，你可能需要启用对等网络同步。
你可以将以下选项添加到 &lt;code&gt;op-node&lt;/code&gt; 命令以启用与特定节点的对等网络同步：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  --p2p.static=&amp;lt;nodes&amp;gt; \
  --p2p.listen.ip=0.0.0.0 \
  --p2p.listen.tcp=9003 \
  --p2p.listen.udp=9003 \
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:::info
你也可以选择删除 &lt;a href=&quot;/builders/node-operators/configuration/consensus-config#p2pstatic&quot;&gt;--p2p.static&lt;/a&gt; 选项，但你可能会看到来自使用相同链 ID 的其他链的失败请求。
:::&lt;/p&gt;
&lt;p&gt;&amp;lt;/Steps&amp;gt;&lt;/p&gt;
&lt;h2&gt;启动 &lt;code&gt;op-batcher&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;op-batcher&lt;/code&gt; 从 Sequencer 获取交易并将这些交易发布到 L1。
一旦这些 Sequencer 交易包含在最终的 L1 区块中，它们就正式成为规范链的一部分。
&lt;code&gt;op-batcher&lt;/code&gt; 至关重要！&lt;/p&gt;
&lt;p&gt;最好为 &lt;code&gt;Batcher&lt;/code&gt; 地址提供至少 1 个 Sepolia ETH，以确保它可以继续运行而不会耗尽用于 gas 的 ETH。
请密切关注 &lt;code&gt;Batcher&lt;/code&gt; 地址的余额，因为如果有大量交易要发布，它可能会快速消耗 ETH。&lt;/p&gt;
&lt;p&gt;&amp;lt;Steps&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;打开一个新的终端&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;你需要一个终端窗口来运行 &lt;code&gt;op-batcher&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;导航到 op-batcher 目录&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd ~/optimism/op-batcher
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;运行 op-batcher&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./bin/op-batcher \
  --l2-eth-rpc=http://localhost:8545 \
  --rollup-rpc=http://localhost:9545 \
  --poll-interval=1s \
  --sub-safety-margin=6 \
  --num-confirmations=1 \
  --safe-abort-nonce-too-low-count=3 \
  --resubmission-timeout=30s \
  --rpc.addr=0.0.0.0 \
  --rpc.port=8548 \
  --rpc.enable-admin \
  --max-channel-duration=25 \
  --l1-eth-rpc=$L1_RPC_URL \
  --private-key=$GS_BATCHER_PRIVATE_KEY
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:::info
&lt;a href=&quot;/builders/chain-operators/configuration/batcher#set-your--op_batcher_max_channel_duration&quot;&gt;&lt;code&gt;--max-channel-duration=n&lt;/code&gt;&lt;/a&gt; 设置告诉 batcher 每 &lt;code&gt;n&lt;/code&gt; 个 L1 区块将所有数据写入 L1。
当它较低时，交易会频繁写入 L1，其他节点可以从 L1 快速同步。
当它较高时，交易写入 L1 的频率较低，并且 batcher 消耗的 ETH 较少。
如果你想降低成本，请将此值设置为 0 以禁用它，或将其增加到更高的值。
:::&lt;/p&gt;
&lt;p&gt;&amp;lt;/Steps&amp;gt;&lt;/p&gt;
&lt;h2&gt;启动 &lt;code&gt;op-proposer&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;现在启动 &lt;code&gt;op-proposer&lt;/code&gt;，它会提出新的状态根。&lt;/p&gt;
&lt;p&gt;&amp;lt;Steps&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;打开一个新的终端&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;打开一个新终端窗口来运行 &lt;code&gt;op-proposer&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;导航到 op-proposer 目录&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd ~/optimism/op-proposer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;运行 op-proposer&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./bin/op-proposer \
  --poll-interval=12s \
  --rpc.port=8560 \
  --rollup-rpc=http://localhost:9545 \
  --l2oo-address=$(cat ../packages/contracts-bedrock/deployments/getting-started/.deploy | jq -r .L2OutputOracleProxy) \
  --private-key=$GS_PROPOSER_PRIVATE_KEY \
  --l1-eth-rpc=$L1_RPC_URL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Steps&amp;gt;&lt;/p&gt;
&lt;h2&gt;将你的钱包连接到你的链&lt;/h2&gt;
&lt;p&gt;现在拥有一个功能齐全的 OP Stack Rollup，其 Sequencer 节点在 &lt;code&gt;http://localhost:8545&lt;/code&gt; 上运行。
你可以像将钱包连接到任何其他 EVM 链一样将钱包连接到此链。
如果你需要一种连接到你的链的简单方法，只需&lt;a href=&quot;https://chainid.link?network=opstack-getting-started&quot;&gt;单击此处&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;在你的链上获取 ETH&lt;/h2&gt;
&lt;p&gt;连接钱包后，你可能会注意到你没有任何 ETH 来支付链上的 gas 费用。
将 Sepolia ETH 存入你的链的最简单方法是将 ETH 直接发送到 &lt;code&gt;L1StandardBridge&lt;/code&gt; 合约。&lt;/p&gt;
&lt;p&gt;&amp;lt;Steps&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;导航到 contracts-bedrock 目录&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd ~/optimism/packages/contracts-bedrock
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;获取 L1StandardBridgeProxy 合约的地址&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat deployments/getting-started/.deploy | jq -r .L1StandardBridgeProxy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;h4&amp;gt;向 L1StandardBridgeProxy 合约发送一些 Sepolia ETH&amp;lt;h4&amp;gt;&lt;/p&gt;
&lt;p&gt;获取 L1 桥接代理合约地址，并使用你希望在 Rollup 上拥有 ETH 的钱包，在 Sepolia 上向该地址发送少量 ETH（0.1 或更少即可）。
这将触发存款，从而在 L2 上将 ETH 铸造到你的钱包中。
ETH 可能需要长达 5 分钟才能显示在你在 L2 上的钱包中。&lt;/p&gt;
&lt;p&gt;&amp;lt;/Steps&amp;gt;&lt;/p&gt;
&lt;h2&gt;查看 rollup 运行情况&lt;/h2&gt;
&lt;p&gt;现在可以像与任何其他 EVM 链交互一样与你的 Rollup 交互。
发送一些交易，部署一些合约，可以与L1进行交互。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Windows 11 下的 WSL2 开发环境：安装 Fedora 40、配置代理和镜像网络</title><link>https://blog.ithuo.net/posts/setting-up-wsl2-with-fedora-40-on-windows-11-proxy-configuration-and-mirrored-networking/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/setting-up-wsl2-with-fedora-40-on-windows-11-proxy-configuration-and-mirrored-networking/</guid><pubDate>Mon, 08 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在当今的开发环境中，&lt;code&gt;Windows Subsystem for Linux (WSL)&lt;/code&gt; 已成为 Windows 用户进行 Linux 开发的首选工具。本文将指导您如何在 Windows 11 上快速设置 &lt;code&gt;WSL2&lt;/code&gt; 环境，安装 &lt;code&gt;Fedora 40&lt;/code&gt;，配置代理，并解释镜像网络的概念及其优势。&lt;/p&gt;
&lt;h2&gt;1. 安装 WSL2&lt;/h2&gt;
&lt;p&gt;首先，我们需要在 &lt;code&gt;Windows 11&lt;/code&gt; 上安装 &lt;code&gt;WSL2&lt;/code&gt;。以管理员身份打开 &lt;code&gt;PowerShell&lt;/code&gt;，然后运行以下命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wsl --install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个命令会自动安装 WSL2 和默认的 Ubuntu 发行版。安装完成后重启电脑。&lt;/p&gt;
&lt;h2&gt;2. 安装 Fedora 40&lt;/h2&gt;
&lt;p&gt;虽然 WSL 默认安装 &lt;code&gt;Ubuntu&lt;/code&gt;，但我们可以轻松切换到 &lt;code&gt;Fedora 40&lt;/code&gt;。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;首先，在 &lt;code&gt;Microsoft Store&lt;/code&gt; 中搜索并安装 &quot;&lt;code&gt;Fedora Remix for WSL&lt;/code&gt;&quot;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;安装完成后，打开 &lt;code&gt;PowerShell&lt;/code&gt; 并运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wsl --set-default Fedora-40
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;启动 Fedora：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wsl -d Fedora-40
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;3. 配置代理&lt;/h2&gt;
&lt;p&gt;在 WSL2 中配置代理可以让您的 &lt;code&gt;Linux&lt;/code&gt; 环境使用 &lt;code&gt;Windows&lt;/code&gt; 主机的网络设置。&lt;/p&gt;
&lt;p&gt;在旧的版本还需要手动配置&lt;code&gt;http/https&lt;/code&gt;代理，现在最新版支持&lt;strong&gt;镜像网络&lt;/strong&gt;模式，在后文有介绍&lt;/p&gt;
&lt;h2&gt;4. 验证代理设置&lt;/h2&gt;
&lt;p&gt;要验证 &lt;code&gt;WSL2&lt;/code&gt; 是否正在使用 &lt;code&gt;Windows&lt;/code&gt; 主机的代理，可以执行以下步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;在 Fedora 终端中运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -I &amp;lt;https://www.google.com&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果看到成功的 HTTP 响应（状态码 200），说明代理配置正确。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP/1.1 200 Connection established

HTTP/2 200
content-type: text/html; charset=ISO-8859-1
content-security-policy-report-only: object-src &apos;none&apos;;base-uri &apos;self&apos;;script-src &apos;nonce-VlovGaKtTZ0GQAslKYYBEQ&apos; &apos;strict-dynamic&apos; &apos;report-sample&apos; &apos;unsafe-eval&apos; &apos;unsafe-inline&apos; https: http:;report-uri https://csp.withgoogle.com/csp/gws/other-hp
p3p: CP=&quot;This is not a P3P policy! See g.co/p3phelp for more info.&quot;
date: Wed, 24 Jul 2024 10:20:18 GMT
server: gws
x-xss-protection: 0
x-frame-options: SAMEORIGIN
expires: Wed, 24 Jul 2024 10:20:18 GMT
cache-control: private
set-cookie: AEC=AVYB7cpAJfuhUWhRO2oYW8hMAEubSO2uQHYMMifnY0QwTyqMWWCr_PHYLNk; expires=Mon, 20-Jan-2025 10:20:18 GMT; path=/; domain=.google.com; Secure; HttpOnly; SameSite=lax
set-cookie: NID=516=h8MC0Bu7dJuDZqd8V5IUIsvUbzDV3WUZ7kVdutb4iFbLOC0oAe8TyOzBmN5DS_aMYq6lPBvxnAH2jn8aE3v9Fun5Vr4824hW3X44bs6XQIifmiK0TDYzWQufzqWdDLbC-oaa45SHKfktYbMHEHRUU-KHv8m8r7r93bMc5MDOGns; expires=Thu, 23-Jan-2025 10:20:18 GMT; path=/; domain=.google.com; HttpOnly
alt-svc: h3=&quot;:443&quot;; ma=2592000,h3-29=&quot;:443&quot;; ma=2592000
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;您还可以检查环境变量：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo $http_proxy
echo $https_proxy
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;5. 配置开发环境&lt;/h2&gt;
&lt;p&gt;接下来，让我们设置一个基本的开发环境：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;更新系统：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo dnf update -y
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;安装常用开发工具：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo dnf install -y git vim nodejs npm python3 python3-pip
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;安装 &lt;code&gt;Visual Studio Code WSL&lt;/code&gt; 扩展（在 Windows 中的 VS Code 里安装）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;6. 镜像网络模式&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;WSL2&lt;/code&gt; 的镜像网络模式是 &lt;code&gt;Windows 11&lt;/code&gt; 中引入的新功能，它提供了更好的网络集成和性能。&lt;/p&gt;
&lt;h3&gt;什么是镜像网络？&lt;/h3&gt;
&lt;p&gt;镜像网络模式使 WSL2 实例能够与 Windows 主机共享相同的网络命名空间。这意味着：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;WSL2&lt;/code&gt; 和 &lt;code&gt;Windows&lt;/code&gt; 使用相同的 IP 地址&lt;/li&gt;
&lt;li&gt;端口转发变得更加简单&lt;/li&gt;
&lt;li&gt;网络性能得到提升&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;启用镜像网络&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;在 Windows 中创建或编辑 &lt;code&gt;%UserProfile%\\.wslconfig&lt;/code&gt; 文件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[wsl2]
networkingMode=mirrored
dnsTunneling=true
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在 PowerShell 中重启 WSL：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wsl --shutdown
wsl
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;验证镜像网络&lt;/h3&gt;
&lt;p&gt;在 Fedora 终端中运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ip addr
----------------------------------------------------------------------------------------
1: lo: &amp;lt;LOOPBACK,UP,LOWER_UP&amp;gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet 10.255.255.254/32 brd 10.255.255.254 scope global lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: loopback0: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:15:5d:0f:9c:1c brd ff:ff:ff:ff:ff:ff
3: eth0: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether e0:0a:f6:a3:77:ba brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.102/24 brd 192.168.1.255 scope global noprefixroute eth0
       valid_lft forever preferred_lft forever
    inet6 2409:8a04:1023:6cc0:f87d:79c6:ca07:bd68/128 scope global nodad noprefixroute
       valid_lft forever preferred_lft forever
    inet6 2409:8a04:1023:6cc0:a5c5:dc9e:7ac7:2ccf/64 scope global nodad deprecated noprefixroute
       valid_lft forever preferred_lft 0sec
    inet6 fe80::4a29:8c9a:c6c9:e529/64 scope link nodad noprefixroute
       valid_lft forever preferred_lft forever
 -----------------------------------------------------------------------
 可以看到fedora与宿主机共用一个IP地址，如果要和宿主机互相通信，就直接用localhost/127.1访问，非常方便
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果看到与 Windows 主机相同的 IP 地址，说明镜像网络已成功启用。&lt;/p&gt;
&lt;h2&gt;7. 常见问题及解决方案&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;WSL2 安装失败&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;确保 Windows 11 已更新到最新版本&lt;/li&gt;
&lt;li&gt;在 &lt;code&gt;BIOS&lt;/code&gt; 中启用虚拟化&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;代理设置不生效&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;检查代理 IP 和端口是否正确&lt;/li&gt;
&lt;li&gt;尝试使用 &lt;code&gt;Windows&lt;/code&gt; 主机的 IP 地址（通常是 172.x.x.1）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;镜像网络模式不工作&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;确保 Windows 11 版本支持此功能（需要 22H2 或更高版本）&lt;/li&gt;
&lt;li&gt;检查 &lt;code&gt;.wslconfig&lt;/code&gt; 文件的语法&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;性能问题&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在 &lt;code&gt;.wslconfig&lt;/code&gt; 文件中限制 &lt;code&gt;WSL2&lt;/code&gt; 的资源使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[wsl2]
memory=4GB
processors=2
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;文件系统性能&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;将项目文件存储在 &lt;code&gt;Linux&lt;/code&gt; 文件系统中（&lt;code&gt;/home/your_username/&lt;/code&gt;）而不是 Windows 文件系统（&lt;code&gt;/mnt/c/&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;如果系统盘空间不够，还可以将wsl2的系统镜像存储位置转移到其他盘符，已验证可行&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;结论&lt;/h2&gt;
&lt;p&gt;通过遵循本指南，您应该能够在 Windows 11 上快速设置 WSL2 环境，安装 Fedora 40，配置代理，并利用镜像网络模式的优势。这种设置为开发人员提供了 Windows 和 Linux 的最佳组合，使得跨平台开发变得更加便捷和高效。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>详解Kubernetes的架构与数据流</title><link>https://blog.ithuo.net/posts/kubernetes-architecture-dataflow-explained/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/kubernetes-architecture-dataflow-explained/</guid><pubDate>Sat, 29 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;这本关于 Kubernetes 架构的综合指南旨在通过插图详细解释每个 Kubernetes 组件。&lt;/p&gt;
&lt;p&gt;因此，如果您希望：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;了解 Kubernetes 的架构&lt;/li&gt;
&lt;li&gt;掌握 Kubernetes 的基本概念&lt;/li&gt;
&lt;li&gt;了解 Kubernetes 架构组件&lt;/li&gt;
&lt;li&gt;探索连接这些组件的工作流&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;然后，您会发现此 Kubernetes 架构指南非常有价值。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：为了更好地理解 Kubernetes 架构，有一些先决条件请查看 kubernetes 学习指南中的先决条件以了解更多信息。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;什么是 Kubernetes 架构？&lt;/h1&gt;
&lt;p&gt;以下 Kubernetes 架构图显示了 Kubernetes 集群的所有组件以及外部系统如何连接到 Kubernetes 集群。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/7dd3fa91097e35ce68295b3808eec7da.png&quot; alt=&quot;20240717150441.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;关于 Kubernetes，您应该了解的第一件事是，它是一个分布式系统。这意味着，它有多个组件分布在网络上的不同服务器上。这些服务器可以是虚拟机或裸机服务器。我们称之为 Kubernetes 集群。&lt;/p&gt;
&lt;p&gt;Kubernetes 集群由控制平面节点和工作节点组成。&lt;/p&gt;
&lt;h3&gt;控制平面&lt;/h3&gt;
&lt;p&gt;控制平面负责容器编排和维护集群的所需状态。它具有以下组件。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;kube-apiserver&lt;/li&gt;
&lt;li&gt;etcd&lt;/li&gt;
&lt;li&gt;kube-scheduler&lt;/li&gt;
&lt;li&gt;kube-controller-manager&lt;/li&gt;
&lt;li&gt;cloud-controller-manager&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;一个集群可以有一个或多个控制平面节点。&lt;/p&gt;
&lt;h3&gt;工作节点&lt;/h3&gt;
&lt;p&gt;Worker 节点负责运行容器化应用程序。worker 节点具有以下组件。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;kubelet&lt;/li&gt;
&lt;li&gt;kube-proxy&lt;/li&gt;
&lt;li&gt;Container runtime&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Kubernetes 控制平面组件&lt;/h1&gt;
&lt;p&gt;首先，让我们看一下每个控制平面组件以及每个组件背后的重要概念。&lt;/p&gt;
&lt;h3&gt;1. kube-apiserver&lt;/h3&gt;
&lt;p&gt;kube-apiserver 是公开 Kubernetes API 的 Kubernetes 集群的中心枢纽。它具有高度可扩展性，可以处理大量并发请求。&lt;/p&gt;
&lt;p&gt;最终用户和其他集群组件通过 API 服务器（kube-apiserver）与集群通信。在极少数情况下，监控系统和第三方服务可能会与 apiserver 通信以与集群进行交互。&lt;/p&gt;
&lt;p&gt;因此，当您使用 kubectl 管理集群时，在后端，您实际上是通过 HTTP REST API 与 API 服务器进行通信。但是，内部集群组件（如 scheduler、controller 等）使用 gRPC 与 API 服务器通信。&lt;/p&gt;
&lt;p&gt;API 服务器与集群中的其他组件之间的通信通过 TLS 进行，以防止对集群进行未经授权的访问。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/e166357b252b86d862caa65323c263fb.png&quot; alt=&quot;20240717151952.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Kubernetes api-server 负责以下工作。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;API 管理：公开集群 API endpoint 并处理所有 API 请求。API 是版本化的，它同时支持多个 API 版本。&lt;/li&gt;
&lt;li&gt;身份验证（使用客户端证书、持有者令牌和 HTTP 基本身份验证）和授权（ABAC 和 RBAC）&lt;/li&gt;
&lt;li&gt;处理 API 请求并验证 API 对象（如 Pod、服务等）的数据（验证和变更准入控制器）&lt;/li&gt;
&lt;li&gt;它是唯一与 etcd 通信的组件&lt;/li&gt;
&lt;li&gt;api-server 协调控制平面和工作节点组件之间的所有进程&lt;/li&gt;
&lt;li&gt;api-server 有一个内置的 apiserver 代理。它是 API 服务器进程的一部分。它主要用于启用从群集外部访问 ClusterIP 服务，即使这些服务通常只能在群集本身内访问&lt;/li&gt;
&lt;li&gt;API 服务器还包含一个聚合层，允许您扩展 Kubernetes API 以创建自定义 API、资源和控制器&lt;/li&gt;
&lt;li&gt;API 服务器还支持监视资源的更改。例如，客户端可以对特定资源建立监视，并在创建、修改或删除这些资源时接收实时通知&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;安全说明：为了减少群集攻击面，保护 API 服务器至关重要。Shadowserver 基金会进行了一项实验，发现了 380,000 个可公开访问的 Kubernetes API 服务器。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;2. etcd&lt;/h3&gt;
&lt;p&gt;Kubernetes 是一个分布式系统，它需要一个高效的分布式数据库，如 etcd 来支持其分布式性质。它既充当后端服务发现，又充当数据库。你可以称它为 Kubernetes 集群的大脑。&lt;/p&gt;
&lt;p&gt;etcd 是一个开源的强一致性分布式键值存储。那么这意味着什么呢？&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;强一致性：如果对某个节点进行了更新，则强一致性将确保它立即更新到群集中的所有其他节点。此外，如果你看一下CAP定理，就不可能实现100%的可用性，并具有很强的一致性和分区容错&lt;/li&gt;
&lt;li&gt;分布式：etcd 被设计为在不牺牲一致性的情况下作为集群在多个节点上运行&lt;/li&gt;
&lt;li&gt;键值存储：将数据存储为键和值的非关系数据库。它还公开键值 API。数据存储建立在 BboltDB 之上，BboltDB 是 BoltDB 的一个分支&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;etcd 使用 raft 共识算法，具有很强的一致性和可用性。它以领导者成员的方式工作，以实现高可用性并承受节点故障。&lt;/p&gt;
&lt;p&gt;那么 etcd 是如何与 Kubernetes 一起工作的呢？&lt;/p&gt;
&lt;p&gt;简单地说，当你使用 kubectl 获取 kubernetes 对象详细信息时，你是从 etcd 获取的。此外，当您部署像 pod 这样的对象时，会在 etcd 中创建一个条目。&lt;/p&gt;
&lt;p&gt;简而言之，这是您需要了解的有关 etcd 的信息。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;etcd 存储 Kubernetes 对象的所有配置、状态和元数据（pod、secret、daemonsets、deployments、configmaps、statefulsets 等）。&lt;/li&gt;
&lt;li&gt;etcd 允许客户端使用 Watch() API 订阅事件。Kubernetes api-server 使用 etcd 的监视功能来跟踪对象状态的变化。&lt;/li&gt;
&lt;li&gt;etcd 使用 gRPC 公开键值 API。此外，&lt;a href=&quot;https://etcd.io/docs/v3.3/dev-guide/api_grpc_gateway/&quot;&gt;gRPC 网关&lt;/a&gt;是一个 RESTful 代理，可将所有 HTTP API 调用转换为 gRPC 消息。这使它成为 Kubernetes 的理想数据库。&lt;/li&gt;
&lt;li&gt;etcd 以键值格式存储所有对象，在 /registry 目录项下。例如，可以在 /registry/pods/default/nginx 下找到默认命名空间中名为 Nginx 的 Pod 的信息&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/3b66a3d26e125b606746981b3190510e.png&quot; alt=&quot;20240717155017.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;此外，etcd 是控制平面中唯一的 Statefulset 组件。&lt;/p&gt;
&lt;h3&gt;3. kube-scheduler&lt;/h3&gt;
&lt;p&gt;kube-scheduler 负责在工作节点上调度 Kubernetes Pod。&lt;/p&gt;
&lt;p&gt;部署容器时，您可以指定容器要求，例如 CPU、内存、关联性、污点或容错、优先级、持久卷 （PV） 等。调度程序的主要任务是识别创建请求，并为满足要求的 Pod 选择最佳节点。&lt;/p&gt;
&lt;p&gt;下图显示了调度程序工作原理的概述。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/a8c8a8fd773887349c5d5a8c6572aac9.png&quot; alt=&quot;20240717192241.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在 Kubernetes 集群中，将有多个工作节点。那么调度程序是如何从所有工作节点中选择节点的呢？以下是调度程序的工作原理。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;为了选择最佳节点，Kube-scheduler 使用过滤和评分操作。&lt;/li&gt;
&lt;li&gt;在筛选中，调度程序会找到最适合调度 Pod 的节点。例如，如果有 5 个节点有充足资源来运行 Pod，则它会选择所有 5 个节点。如果没有节点，则 Pod 不可调度并移动到调度队列。如果它是一个大型集群，假设有 100 个工作节点，并且调度程序不会遍历所有节点。有一个名为 percentageOfNodesToScore 的调度器配置参数。默认值通常为 50%。因此，它试图以循环方式迭代超过 50% 的节点。如果工作器节点分布在多个区域中，则调度程序将遍历不同区域中的节点。对于非常大的集群，默认 percentageOfNodesToScore 值为 5%。&lt;/li&gt;
&lt;li&gt;在评分阶段，调度程序通过向筛选的工作器节点分配分数来对节点进行排名。调度程序通过调用多个调度插件进行评分。最后，将选择排名最高的 worker 节点来调度 pod。如果所有节点的排名相同，则将随机选择一个节点。&lt;/li&gt;
&lt;li&gt;选择节点后，调度程序将在 API 服务器中创建绑定事件。表示绑定 Pod 和节点的事件。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;有关调度程序，你需要了解：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;它是一个控制器，用于侦听 API 服务器中的 Pod 创建事件。&lt;/li&gt;
&lt;li&gt;调度程序有两个阶段。调度周期和绑定周期。统称为调度上下文。调度周期选择工作器节点，绑定周期将该更改应用于集群。&lt;/li&gt;
&lt;li&gt;调度程序始终将高优先级的 Pod 放在低优先级的 Pod 之前进行调度。此外，在某些情况下，在 Pod 开始在所选节点中运行后，Pod 可能会被逐出或移动到其他节点。如果您想了解更多信息，请阅读 &lt;a href=&quot;https://devopscube.com/pod-priorityclass-preemption/&quot;&gt;Kubernetes Pod 优先级指南&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;您可以创建自定义调度程序，并在集群中运行多个调度程序以及原生调度程序。部署 Pod 时，您可以在 Pod 清单中指定自定义调度程序。因此，调度决策将基于自定义调度程序逻辑进行。&lt;/li&gt;
&lt;li&gt;调度程序具有可插拔的调度框架。这意味着，您可以将自定义插件添加到调度工作流程中。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;4. Kube Controller Manager&lt;/h3&gt;
&lt;p&gt;什么是控制器？控制器是运行无限控制循环的程序。这意味着它连续运行并监视对象的实际和所需状态。如果实际状态和期望状态存在差异，则确保 kubernetes 资源/对象处于期望状态。&lt;/p&gt;
&lt;p&gt;根据官方文件，&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在 Kubernetes 中，控制器是监视集群状态的控制循环，然后在需要时进行更改或请求更改。每个控制器都尝试将当前集群状态移近所需状态。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;假设要创建部署，在清单 YAML 文件中指定所需的状态（声明性方法）。例如，2 个副本、1 个卷挂载、configmap 等。内置的部署控制器可确保部署始终处于所需状态。如果用户使用 5 个副本更新部署，则部署控制器会识别它并确保所需的状态为 5 个副本。&lt;/p&gt;
&lt;p&gt;Kube Controller Manager 是管理所有 Kubernetes 控制器的组件。Kubernetes 资源/对象（如 Pod、命名空间、作业、副本集）由各自的控制器管理。此外，Kube-Scheduler 也是一个由 Kube-Controller-Manager 管理的控制器。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/f55ec862156be4c123e11d15e3da8cfb.png&quot; alt=&quot;20240717195129.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;以下是重要的内置 Kubernetes 控制器列表。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Deployment controller&lt;/li&gt;
&lt;li&gt;ReplicaSet controller&lt;/li&gt;
&lt;li&gt;DaemonSet controller&lt;/li&gt;
&lt;li&gt;Job controller&lt;/li&gt;
&lt;li&gt;CronJob controller&lt;/li&gt;
&lt;li&gt;endpoints controller&lt;/li&gt;
&lt;li&gt;namespace controller&lt;/li&gt;
&lt;li&gt;service account controller&lt;/li&gt;
&lt;li&gt;Node controller&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;以下是您应该了解的有关 Kube Controller Manager 的信息。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;它管理所有控制器，控制器尝试将集群保持在所需状态。&lt;/li&gt;
&lt;li&gt;您可以使用与自定义资源定义关联的自定义控制器来扩展 kubernetes。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;5. Cloud Controller Manager（CCM）&lt;/h3&gt;
&lt;p&gt;在云环境中部署 kubernetes 时，云控制器管理器充当云平台 API 和 Kubernetes 集群之间的桥梁。&lt;/p&gt;
&lt;p&gt;这样，kubernetes 核心组件可以独立工作，并允许云提供商使用插件与 kubernetes 集成。（例如，kubernetes 集群和 AWS 云 API 之间的接口）&lt;/p&gt;
&lt;p&gt;云控制器集成允许 Kubernetes 集群预置云资源，例如实例（用于节点）、负载均衡器（用于服务）和存储卷（用于持久卷）。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/a15956802184d475a0ed66a8302308a3.png&quot; alt=&quot;20240717200010.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;云控制器管理器包含一组特定于云平台的控制器，可确保特定于云的组件（节点、负载均衡器、存储等）处于所需状态。以下是云控制器管理器中的三个主要控制器。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;节点控制器（Node controller）：此控制器通过与云提供商 API 通信来更新与节点相关的信息。例如，节点标记和注释，获取主机名，CPU和内存可用性，节点运行状况等。&lt;/li&gt;
&lt;li&gt;路由控制器（Route controller）：负责在云平台上配置组网路由。这样不同节点的 Pod 就可以相互通信。&lt;/li&gt;
&lt;li&gt;服务控制器（Service controller）：它负责为 kubernetes 服务部署负载均衡器、分配 IP 地址等。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;以下是云控制器管理器的一些经典示例。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;部署负载均衡器类型的 Kubernetes 服务。在这里，Kubernetes 预置了特定于云的负载均衡器，并与 Kubernetes 服务集成。&lt;/li&gt;
&lt;li&gt;为云存储解决方案支持的 Pod 配置存储卷 （PV）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;总体而言，Cloud Controller Manager 管理 Kubernetes 使用的云特定资源的生命周期。&lt;/p&gt;
&lt;h1&gt;Kubernetes 工作节点组件&lt;/h1&gt;
&lt;p&gt;现在，让我们看一下工作节点上的组件。&lt;/p&gt;
&lt;h3&gt;1. Kubelet&lt;/h3&gt;
&lt;p&gt;Kubelet 是一个 Agent 组件，运行在集群中的每个节点上。Kubelet 不作为容器运行，而是作为守护程序运行，由 systemd 管理。&lt;/p&gt;
&lt;p&gt;它负责向 API 服务器注册工作节点，并主要从 API 服务器使用 podSpec（Pod 规范 – YAML 或 JSON）。podSpec 定义了应在 Pod 内运行的容器、它们的资源（例如 CPU 和内存限制）以及其他设置，例如环境变量、卷和标签。&lt;/p&gt;
&lt;p&gt;然后，它通过创建容器将 podSpec 带到所需状态。&lt;/p&gt;
&lt;p&gt;Kubelet 负责以下工作。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;创建、修改和删除容器。&lt;/li&gt;
&lt;li&gt;负责处理活跃度、准备情况和启动探测。&lt;/li&gt;
&lt;li&gt;负责通过读取 Pod 配置并在主机上为卷挂载创建相应的目录来挂载卷。&lt;/li&gt;
&lt;li&gt;通过调用 API 服务器来收集和报告节点和 Pod 状态 ，实现方式为 cAdvisor 和 CRI。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Kubelet 也是一个控制器，它监视 Pod 的变化，并利用节点的容器运行时来拉取镜像、运行容器等。&lt;/p&gt;
&lt;p&gt;除了来自 API 服务器的 PodSpec 之外，Kubelet 还可以接受来自文件、HTTP 端点和 HTTP 服务器的 podSpec。“来自文件的 podSpec”的一个很好的例子是 Kubernetes 静态 pod。&lt;/p&gt;
&lt;p&gt;静态 Pod 由 Kubelet 控制，而不是由 API 服务器控制。这意味着您可以通过向 Kubelet 组件提供 Pod YAML 位置来创建 Pod。但是，Kubelet 创建的静态 Pod 不受 API 服务器的管理。下面是静态 Pod 的真实示例用例。&lt;/p&gt;
&lt;p&gt;在启动控制平面各组件时，kubelet 从 /etc/kubernetes/manifests 读取 podSpecs，启动 api-server、scheduler 和 controller-manager 作为静态 pod。&lt;/p&gt;
&lt;p&gt;以下是关于 kubelet 的一些关键内容。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Kubelet 使用 CRI（容器运行时接口）gRPC 接口与容器运行时通信。&lt;/li&gt;
&lt;li&gt;它还公开 HTTP 终结点以流式传输日志，并为客户端提供 exec 会话。&lt;/li&gt;
&lt;li&gt;使用 CSI（容器存储接口）gRPC 配置块存储卷。&lt;/li&gt;
&lt;li&gt;它使用集群中配置的 CNI 插件来分配 Pod IP 地址，并为 Pod 设置任何必要的网络路由和防火墙规则。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/ba2b6d0edbde5c5ba911f76d7c04bfc6.png&quot; alt=&quot;20240718085632.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;2. Kube proxy&lt;/h3&gt;
&lt;p&gt;要了解 Kube proxy，您需要对 Kubernetes 服务和端点对象有基本的了解。&lt;/p&gt;
&lt;p&gt;Kubernetes 中的服务是一种在内部或向外部流量公开一组 Pod 的方法。创建服务对象时，它会为其分配一个虚拟 IP。它被称为 clusterIP。它只能在 Kubernetes 集群中访问。&lt;/p&gt;
&lt;p&gt;Endpoint 对象包含 Service 对象下 Pod 组的所有 IP 地址和端口。端点控制器负责维护容器 IP 地址（端点）列表。服务控制器负责为服务配置端点。&lt;/p&gt;
&lt;p&gt;您无法 ping ClusterIP，因为它仅用于服务发现，这与可 ping 的 Pod IP 不同。&lt;/p&gt;
&lt;p&gt;现在让我们了解一下 Kube Proxy。&lt;/p&gt;
&lt;p&gt;Kube-proxy 是一个守护进程，它作为 daemonset 在每个节点上运行。它是一个代理组件，用于实现 Pod 的 Kubernetes 服务概念。（具有负载均衡功能的一组 Pod 的单个 DNS）。它主要代理 UDP、TCP 和 SCTP，不理解 HTTP。&lt;/p&gt;
&lt;p&gt;当您使用 Service （ClusterIP） 公开 Pod 时，Kube-proxy 会创建网络规则，将流量发送到 Service 对象下分组的后端 Pod（端点）。这意味着，所有负载均衡和服务发现都由 Kube proxy 处理。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;那么 Kube-proxy 是如何工作的呢？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Kube proxy 与 API 服务器通信，以获取有关服务 （ClusterIP） 和相应 Pod IP 和端口（端点）的详细信息。它还监视服务和端点的更改。&lt;/p&gt;
&lt;p&gt;然后，kube-proxy 使用以下任一模式创建/更新规则，将流量路由到 Service 后面的 Pod。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;IPTables：这是默认模式。在 IPTables 模式量由 IPtable 规则处理。这意味着，对于每个服务，都会创建 IPtable 规则。这些规则捕获进入 ClusterIP 的流量，然后将其转发到后端 Pod。此外，在这种模式下，kube-proxy 会随机选择后端 pod 进行负载均衡。建立连接后，请求将转到同一 Pod，直到连接终止。&lt;/li&gt;
&lt;li&gt;IPVS：对于服务超过 1000 的集群，IPVS 提供性能改进。它支持以下后端负载均衡算法。
&lt;ol&gt;
&lt;li&gt;rr ：这是默认模式。&lt;/li&gt;
&lt;li&gt;lc ：最少连接数（最小打开连接数）&lt;/li&gt;
&lt;li&gt;dh ：目标哈希&lt;/li&gt;
&lt;li&gt;sh ：源哈希&lt;/li&gt;
&lt;li&gt;sed ：最短的预期延迟&lt;/li&gt;
&lt;li&gt;nq ：从不排队&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Userspace：用户空间（旧版和不推荐）&lt;/li&gt;
&lt;li&gt;Kernelspace：此模式仅适用于 Windows 系统。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/699d3e5cc8760207b70f7e4b21cec154.png&quot; alt=&quot;20240718091008.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;如果您想了解 kube-proxy IPtables 和 IPVS 模式之间的性能差异，请&lt;a href=&quot;https://www.tigera.io/blog/comparing-kube-proxy-modes-iptables-or-ipvs/&quot;&gt;阅读本文&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;此外，您可以通过将 Kubernetes 集群替换为 Cilium 来运行没有 kube-proxy 的 Kubernetes 集群。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;1.29 Alpha 功能：Kubeproxy 有一个基于 nftables 的新后端。nftables 是 IPtables 的继任者，旨在更简单、更高效&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;3. Container Runtime&lt;/h3&gt;
&lt;p&gt;您可能了解 Java 运行时 （JRE）。它是在主机上运行 Java 程序所需的软件。同样，容器运行时是运行容器所需的软件组件。&lt;/p&gt;
&lt;p&gt;容器运行时在 Kubernetes 集群中的所有节点上运行。它负责从容器注册表中提取镜像、运行容器、分配和隔离容器资源，以及管理主机上容器的整个生命周期。&lt;/p&gt;
&lt;p&gt;为了更好地理解这一点，让我们看一下两个关键概念：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;容器运行时接口 （CRI）：它是一组 API，允许 Kubernetes 与不同的容器运行时进行交互。它允许不同的容器运行时与 Kubernetes 互换使用。CRI 定义了用于创建、启动、停止和删除容器以及管理映像和容器网络的 API。&lt;/li&gt;
&lt;li&gt;开放容器倡议 （OCI）：它是一组容器格式和运行时的标准。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Kubernetes 支持多个符合容器运行时接口 （CRI） 的容器运行时（CRI-O、Docker Engine、containerd 等）。这意味着，所有这些容器运行时都实现了 CRI 接口，并公开了 gRPC CRI API（运行时和镜像服务端点）。&lt;/p&gt;
&lt;p&gt;那么 Kubernetes 是如何利用容器运行时的呢？&lt;/p&gt;
&lt;p&gt;正如我们在 Kubelet 部分所了解的，kubelet 代理负责使用 CRI API 与容器运行时进行交互，以管理容器的生命周期。它还从容器运行时获取所有容器信息，并将其提供给控制平面。&lt;/p&gt;
&lt;p&gt;我们以 CRI-O 容器运行时接口为例。下面是容器运行时如何与 Kubernetes 配合使用的高级概述。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/12b09ea882fdcfeda5955f382053f8a5.png&quot; alt=&quot;20240718091511.png&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;当 API 服务器对 Pod 有新的请求时，kubelet 会与 CRI-O 守护进程通信，以通过 Kubernetes 容器运行时接口启动所需的容器。&lt;/li&gt;
&lt;li&gt;CRI-O 使用 containers/image 库检查并从配置的容器注册表中提取所需的容器映像。&lt;/li&gt;
&lt;li&gt;然后，CRI-O 为容器生成 OCI 运行时规范 （JSON）。&lt;/li&gt;
&lt;li&gt;然后，CRI-O 启动与 OCI 兼容的运行时 （runc） 以根据运行时规范启动容器进程。&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Kubernetes 集群插件组件&lt;/h1&gt;
&lt;p&gt;除了核心组件之外，kubernetes 集群还需要附加组件才能完全运行。选择插件取决于项目要求和应用场景。&lt;/p&gt;
&lt;p&gt;以下是集群上可能需要的一些常用插件组件。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;CNI 插件（容器网络接口）&lt;/li&gt;
&lt;li&gt;CoreDNS（用于 DNS 服务）：CoreDNS 充当 Kubernetes 集群中的 DNS 服务器。通过启用此插件，您可以启用基于 DNS 的服务发现。&lt;/li&gt;
&lt;li&gt;Metrics Server（用于资源指标）：此插件可帮助您收集集群中节点和 Pod 的性能数据和资源使用情况。&lt;/li&gt;
&lt;li&gt;Web UI（Kubernetes 仪表板）：此插件使 Kubernetes 仪表板能够通过 Web UI 管理对象。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;1. CNI Plugin&lt;/h3&gt;
&lt;p&gt;首先，您需要了解容器网络接口 （CNI）。它是一个基于插件的架构，具有供应商中立的规范和库，用于为容器创建网络接口。它不是特定于 Kubernetes 的。借助 CNI，容器网络可以在 Kubernetes、Mesos、CloudFoundry、Podman、Docker 等容器编排工具之间实现标准化。&lt;/p&gt;
&lt;p&gt;在容器网络方面，公司可能有不同的要求，例如网络隔离、安全性、加密等。随着容器技术的进步，许多网络提供商为具有广泛网络功能的容器创建了基于 CNI 的解决方案。你可以称它为CNI-Plugins。&lt;/p&gt;
&lt;p&gt;这允许用户从不同的提供商处选择最适合其需求的网络解决方案。&lt;/p&gt;
&lt;p&gt;CNI 插件如何与 Kubernetes 配合使用？&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Kube-controller-manager 负责为每个节点分配 Pod 网段。每个 Pod 从 Pod CIDR 获取一个唯一的 IP 地址。&lt;/li&gt;
&lt;li&gt;Kubelet 与容器运行时交互以启动定时 Pod。作为容器运行时一部分的 CRI 插件与 CNI 插件交互以配置 Pod 网络。&lt;/li&gt;
&lt;li&gt;CNI 插件支持使用叠加网络在分布在相同或不同节点上的 Pod 之间联网。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/01f68f41f577a4ed538338c6081e73c8.png&quot; alt=&quot;20240718092536.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;以下是 CNI 插件提供的高级功能。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Pod 网络&lt;/li&gt;
&lt;li&gt;Pod 网络安全和隔离，使用网络策略来控制 Pod 之间和命名空间之间的流量。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;一些流行的 CNI 插件包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Calico&lt;/li&gt;
&lt;li&gt;Flannel&lt;/li&gt;
&lt;li&gt;Weave Net&lt;/li&gt;
&lt;li&gt;Cilium(Uses eBPF)&lt;/li&gt;
&lt;li&gt;Amazon VPC CNI (For AWS VPC)&lt;/li&gt;
&lt;li&gt;Azure CNI&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Kubernetes 原生对象&lt;/h1&gt;
&lt;p&gt;到目前为止，我们已经了解了核心 kubernetes 组件以及每个组件的工作原理。所有这些组件都致力于管理以下关键 Kubernetes 对象。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pod&lt;/li&gt;
&lt;li&gt;Namespace&lt;/li&gt;
&lt;li&gt;Replicaset&lt;/li&gt;
&lt;li&gt;Deployment&lt;/li&gt;
&lt;li&gt;Daemonset&lt;/li&gt;
&lt;li&gt;Statefulset&lt;/li&gt;
&lt;li&gt;Jobs &amp;amp; Cronjobs&lt;/li&gt;
&lt;li&gt;ConfigMaps &amp;amp; Secrets&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在网络方面，以下 Kubernetes 对象起着关键作用。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Service&lt;/li&gt;
&lt;li&gt;Ingress&lt;/li&gt;
&lt;li&gt;NetworkPolicy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此外，Kubernetes 可以使用 CRD 和自定义控制器进行扩展。因此，群集组件还管理使用自定义控制器和自定义资源定义创建的对象。&lt;/p&gt;
&lt;h1&gt;Kubernetes 架构常见问题解答&lt;/h1&gt;
&lt;h3&gt;Kubernetes 控制平面的主要用途是什么？&lt;/h3&gt;
&lt;p&gt;控制平面负责维护集群及其上运行的应用程序的所需状态。它由 API Server、etcd、Scheduler 和 Controller manager 等组件组成。&lt;/p&gt;
&lt;h3&gt;Kubernetes 集群中工作节点的用途是什么？&lt;/h3&gt;
&lt;p&gt;工作器节点是在群集中运行容器的服务器（裸机或虚拟）。它们由控制平面管理，并从控制平面接收有关如何运行属于 Pod 的容器的指令。&lt;/p&gt;
&lt;h3&gt;如何在 Kubernetes 中保护控制平面和工作节点之间的通信？&lt;/h3&gt;
&lt;p&gt;控制平面和工作节点之间的通信使用 PKI 证书进行保护，不同组件之间的通信通过 TLS 进行。这样，只有受信任的组件才能相互通信。&lt;/p&gt;
&lt;h3&gt;Kubernetes 中 etcd 键值存储的目的是什么？&lt;/h3&gt;
&lt;p&gt;Etcd 主要存储集群的 kubernetes 对象、集群信息、节点信息以及集群的配置数据，例如集群上运行的应用程序的期望状态。&lt;/p&gt;
&lt;h3&gt;如果 etcd 宕机，Kubernetes 应用程序会发生什么？&lt;/h3&gt;
&lt;p&gt;虽然如果 etcd 遇到中断，正在运行的应用程序不会受到影响，但如果没有正常运行的 etcd，将无法创建或更新任何对象。&lt;/p&gt;
&lt;h1&gt;总结&lt;/h1&gt;
&lt;p&gt;了解 Kubernetes 架构有助于您进行日常 Kubernetes 实施和操作。在实施生产级群集设置时，对 Kubernetes 组件有正确的了解将有助于你运行应用程序并对其进行故障排除。接下来，您可以从分步 kubernetes 教程开始，获得 Kubernetes 对象和资源的实践经验。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;本文翻译自：https://devopscube.com/kubernetes-architecture-explained/&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded><author>Derick</author></item><item><title>详解 Kubernetes Pod</title><link>https://blog.ithuo.net/posts/deep-dive-into-kubernetes-pods/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/deep-dive-into-kubernetes-pods/</guid><pubDate>Sat, 29 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/46830582b7374a1761d898995a97c257.png&quot; alt=&quot;20240722181504.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在本指南中，我使用实际示例详细介绍 Kubernetes Pod 概念。如果你想了解如下内容，本指南特别适合你：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pod 核心概念&lt;/li&gt;
&lt;li&gt;如何创建 Pod&lt;/li&gt;
&lt;li&gt;访问 Pod&lt;/li&gt;
&lt;li&gt;Pod 关联对象&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本指南的目的是让您了解如何构建 Pod，并部署 Pod 和访问在其上运行的应用程序。此外，还有许多与 Pod 对象相关的概念。因此，我提供了与 Pod 相关的所有信息和概念，以进一步构建您所学的基础知识。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：在开始探索 Kubernetes Pod 之前，请确保您对 Linux 容器概念有充分的了解。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;什么是 Kubernetes Pod？&lt;/h1&gt;
&lt;p&gt;在了解 Kubernetes Pod 概念之前，让我们先了解一下容器。&lt;/p&gt;
&lt;p&gt;众所周知，容器是一个独立的环境，我们在其中打包应用程序及其依赖项。通常，容器运行单个进程（尽管有多种方法可以运行多个进程）。每个容器都有一个 IP 地址，可以附加卷并控制 CPU 和内存资源等。所有这些都是通过命名空间和控制组（cgroups）的概念发生的。&lt;/p&gt;
&lt;p&gt;Kubernetes 是一个用于部署、扩展和管理容器化应用程序的容器编排系统，它有自己的容器运行方式。我们称之为 Pod。 Pod 是 Kubernetes 中最小的可部署单元，代表应用程序的单个实例。&lt;/p&gt;
&lt;p&gt;例如，如果您想运行 Nginx 应用程序，则可以在 Pod 中运行它。&lt;/p&gt;
&lt;p&gt;那么它与容器有什么不同呢？容器是一个单一的单元。但是，一个 Pod 可以包含多个容器。您可以将 Pod 视为一个可以将一个或多个容器容纳在一起的盒子。&lt;/p&gt;
&lt;p&gt;Pod 提供了更高级别的抽象，允许您将多个容器作为一个单元进行管理。这里，不再是每个容器分别一个 IP，而是 Pod 整体获取一个 IP，然后，Pod 内的多个不同的容器相互之间，使用 localhost 通信。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/d73a9ee5940c28a5c2871ee02ec2df5c.gif&quot; alt=&quot;multi-container-pod.gif&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这意味着 Kubernetes pod 内的容器共享以下内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Network namespace：网络命名空间 – Pod 内的所有容器都通过 localhost 进行通信。&lt;/li&gt;
&lt;li&gt;IPC namespace：IPC 命名空间：所有容器都使用共享的进程间通信命名空间。&lt;/li&gt;
&lt;li&gt;UTS namespace：UTS 命名空间：所有容器共享相同的主机名。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pod 内的容器之间不共享什么？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;默认情况下，PID 命名空间不共享，但是 kubernetes 提供了使用 shareProcessNamespace 选项在 pod 内的容器之间启用进程共享的选项。&lt;/li&gt;
&lt;li&gt;挂载命名空间不在容器之间共享。每个容器都有自己的私有文件系统和目录。但是，Pod 挂载卷在容器之间共享。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;简而言之，以下是您应该了解 pod 的知识：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pod 是 Kubernetes 中最小的可部署单元。&lt;/li&gt;
&lt;li&gt;Pod 本质上是短暂的；它们可以被创建、删除和更新。&lt;/li&gt;
&lt;li&gt;一个 Pod 可以有多个容器；一个 Pod 内可以运行的容器数量没有限制。&lt;/li&gt;
&lt;li&gt;每个 Pod 都有一个唯一的 IP 地址。&lt;/li&gt;
&lt;li&gt;Pod 使用 IP 地址相互通信。&lt;/li&gt;
&lt;li&gt;Pod 内的容器使用不同端口，通过 localhost 进行连接。&lt;/li&gt;
&lt;li&gt;Pod 内运行的容器应具有不同的端口号，以避免端口冲突。&lt;/li&gt;
&lt;li&gt;您可以为 Pod 内运行的每个容器设置 CPU 和内存资源。&lt;/li&gt;
&lt;li&gt;Pod 内的容器共享相同的卷挂载。&lt;/li&gt;
&lt;li&gt;pod内的所有容器都调度在同一个节点上；它不能跨越多个节点。&lt;/li&gt;
&lt;li&gt;如果有多个容器，则在 Pod 启动期间，所有主容器都会并行启动。而 Pod 内的 init 容器按顺序运行。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Pod YAML（对象定义）&lt;/h1&gt;
&lt;p&gt;现在我们对 Pod 有了基本的了解，让我们看看如何定义 Pod。 Pod 是原生 Kubernetes 对象，如果要创建 pod，则需要以 YAML 格式声明 pod 要求。您还可以使用 kubectl 命令创建 pod。我们将在后面的主题中看到这一点。&lt;/p&gt;
&lt;p&gt;以下是创建 Nginx Web 服务器 Pod 的 Pod YAML 示例。此 YAML 只是 pod 的声明性所需状态。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apiVersion: v1
kind: Pod
metadata:
  name: web-server-pod
  labels:
    app: web-server
    environment: production
  annotations:
    description: This pod runs the web server
spec:
  containers:
  - name: web-server
    image: nginx:latest
    ports:
    - containerPort: 80
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;让我们来理解一下这个 pod YAML。一旦您了解了基本的 YAML，您就会更轻松地使用 Pod 和相关对象，例如部署（Deployment）、守护进程集（Daemonset）、状态集（Statefulset）等。每个 Kubernetes 对象都有一些通用的参数集。这些值会根据我们正在创建的对象类型而变化。&lt;/p&gt;
&lt;p&gt;让我们看一下 Kubernetes pod 对象。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;参数&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;描述&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;apiVersion&lt;/td&gt;
&lt;td&gt;pod 的 API 版本。在我们的例子中，它是 v1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kind&lt;/td&gt;
&lt;td&gt;对象的种类，这里是 Pod&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;metadata&lt;/td&gt;
&lt;td&gt;元数据用于唯一标识和描述容器– 标签（表示 Pod 的键值对集）。这类似于云环境中的标记。每个对象都必须使用标准标签进行标记。它有助于对对象进行分组。– name（Pod 的名称）– namespace （pod 的命名空间）– 注解（键值格式的附加数据）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;spec&lt;/td&gt;
&lt;td&gt;在“spec”部分下，我们声明了 pod 的所需状态。这些是我们希望在 pod 中运行的容器的规格。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;containers&lt;/td&gt;
&lt;td&gt;在容器下，我们声明 pod 内容器的所需状态。容器镜像、公开端口等。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;现在，我们已经查看了一个基本的 Pod YAML 清单。请务必注意，此清单支持许多参数。我们将通过动手实践的方法逐步探索这些附加参数。&lt;/p&gt;
&lt;p&gt;现在我们已经对 Pod 有了基本的了解，让我们创建一个 Pod。&lt;/p&gt;
&lt;h1&gt;创建 Pod（实例）&lt;/h1&gt;
&lt;p&gt;您可以通过两种方式创建容器：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 kubectl 命令：主要用于学习和测试目的。命令有其自身的局限性。&lt;/li&gt;
&lt;li&gt;声明性方法：使用 YAML 清单。正儿八经做项目时，使用 YAML 部署 Pod。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;让我们看一下这两个选项。我们将创建一个具有以下内容的 NGINX pod：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pod 的名称是 web-server-pod&lt;/li&gt;
&lt;li&gt;它应该有标签 app： web-server 和 environment： production&lt;/li&gt;
&lt;li&gt;添加注释来描述容器。&lt;/li&gt;
&lt;li&gt;使用 nginx:1.14.2 容器镜像。&lt;/li&gt;
&lt;li&gt;公开容器端口 80。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;使用 kubectl 命令创建 Pod&lt;/h3&gt;
&lt;p&gt;对于所讨论的 pod 要求，这里是 kubectl 命令。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl run web-server-pod \
  --image=nginx:1.14.2 \
  --restart=Never \
  --port=80 \
  --labels=app=web-server,environment=production \
  --annotations description=&quot;This pod runs the web server&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这里，Pod 部署在默认命名空间中。您可以获取已部署的 pod kubectl 的状态。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;kubectl get pods&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;部署容器后，您将看到容器正在运行状态，如下所示。在我们的示例中，pod 内只有一个容器。因此，它显示 1/1 准备就绪并正在运行。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/df30b5767a266a43303a22f829b4b55c.png&quot; alt=&quot;20240722202753.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;查看一个 Pod 的描述&lt;/h3&gt;
&lt;p&gt;如果你想知道正在运行的 pod 的所有细节，你可以使用 kubectl 来查看这个 pod 的描述。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;kubectl describe pod web-server-pod&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;在以下输出中，您可以看到有关容器的所有详细信息。它的 IP 地址、命名空间、容器详细信息、QoS 类等。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/a2c9db1975e7a943212e047bd7c6a779.png&quot; alt=&quot;20240722202918.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;以下是 describe 命令显示的所有重要 Pod 信息的图形视图。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/6f63fc870c3dd3bdaa7d7eb6d3990b1c.gif&quot; alt=&quot;pod-info.gif&quot; /&gt;&lt;/p&gt;
&lt;p&gt;现在，让我们使用以下命令删除 pod。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;kubectl delete pod web-server-pod&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;使用声明式 YAML 创建 Pod&lt;/h3&gt;
&lt;p&gt;在正儿八经做项目时，您主要是通过声明式方法创建 pod。让我们看看如何使用 YAML 清单创建一个 pod。创建一个包含以下内容的文件 nginx.yaml。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apiVersion: v1
kind: Pod
metadata:
  name: web-server-pod
  labels:
    app: web-server
    environment: production
  annotations:
    description: This pod runs the web server
spec:
  containers:
  - name: web-server
    image: nginx:1.14.2
    ports:
    - containerPort: 80
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在，要部署清单，您需要使用文件名执行以下 kubectl 命令。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;kubectl create -f nginx.yaml&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;我们是否应该记住每个参数来创建 YAML？不。您可以使用 –dry-run 标志创建 YAML 文件。下面是一个示例。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;kubectl run nginx-pod --image=nginx:1.14.2 --dry-run=client -o yaml&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;您也可以通过重定向输出把它写入文件。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;kubectl run nginx-pod --image=nginx:1.14.2 --dry-run=client -o yaml &amp;gt; nginx-pod.yaml&lt;/code&gt;&lt;/p&gt;
&lt;h1&gt;访问在 Pod 中运行的应用程序&lt;/h1&gt;
&lt;p&gt;现在我们有一个带有 Nginx Web Server 的运行 pod。整个想法是部署和访问在 pod 中运行的应用程序。&lt;/p&gt;
&lt;p&gt;Kubectl 提供了一个端口转发命令，用于从本地工作站访问 Kubernetes 集群中正在运行的 Pod。&lt;/p&gt;
&lt;p&gt;我们有一个正在运行的 pod，名为 web-server-pod。让我们通过 port-forward 命令访问它。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;kubectl port-forward pod/web-server-pod 8080:80&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;您应该会看到如下所示的输出。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/e0a8cb6c56364cc40f017a033545a38d.png&quot; alt=&quot;20240722204229.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;现在，如果您进入浏览器并访问 http://localhost:8080，您应该会看到 Nginx 主页，如下所示。该网页由我们的 Nginx Web Server 的 pod 提供服务。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/99b8ee4a00bfe681f48c1f7eb54c4c46.png&quot; alt=&quot;20240722204323.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;现在，您可以通过按 CTRL+C 断开端口转发。&lt;/p&gt;
&lt;p&gt;运行 kubectl port-forward 时，发生了什么：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kubectl 绑定本地系统中的指定端口。在我们的例子中，它是 8080。&lt;/li&gt;
&lt;li&gt;然后，它与 Kubernetes 集群 API 通信，以建立到所需节点的隧道（单个 HTTP 连接），然后连接到指定的 Pod 和容器端口，即 80。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：kubectl 端口转发更像是一个调试实用程序。您需要使用 Kubernetes Service 对象来公开在 Pod 中运行的应用程序。我们将在另一篇博客中实际了解 Kubernetes 服务概念&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;访问 Pod Shell&lt;/h1&gt;
&lt;p&gt;我们已经学习了如何访问在 pod 中运行的应用程序。现在，如果您想访问 pod shell，该怎么办？在许多用例中，您需要终端访问容器。一个主要场景是调试和故障排除。这就是 kubectl exec 命令派上用场的地方。您可以使用以下命令访问 web-server-pod 的 shell。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;kubectl exec -it web-server-pod -- /bin/sh&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;在以下输出中，我正在 pod 内执行 whoami 命令。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/bec07a57bc841f71af0da065c6c8330f.png&quot; alt=&quot;20240722204827.png&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：容器镜像通常被设计为非常小，因此您可能会发现无法执行在普通 Linux 系统上执行的所有命令。此限制取决于镜像的生成方式以及容器镜像中包含的工具程序。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;Pod 生命周期&lt;/h1&gt;
&lt;p&gt;关于 Pod 你应该知道的另一个重要概念是它的生命周期。&lt;/p&gt;
&lt;p&gt;Pod 通常由 ReplicaSet Controller、Deployment Controller 等控制器管理。使用 YAML 创建单个 Pod 时，它不受任何控制器的管理。在这两种情况下，Pod 都会经历不同的生命周期阶段。&lt;/p&gt;
&lt;p&gt;以下是 Pod 生命周期阶段。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pending：表示 Pod 创建请求成功，但调度正在进行中。例如，它正在下载容器映像。&lt;/li&gt;
&lt;li&gt;Running：容器已成功运行并按预期运行。例如，Pod 是服务客户端请求。&lt;/li&gt;
&lt;li&gt;Succeeded：容器内的所有容器都已成功终止。例如，成功完成 CronJob 对象。&lt;/li&gt;
&lt;li&gt;Failed：所有 Pod 都已终止，但至少有一个容器因失败而终止。例如，由于配置问题，在 Pod 内运行的应用程序无法启动，并且容器以非零退出代码退出。&lt;/li&gt;
&lt;li&gt;Unknown：容器状态未知。例如，集群无法监控 Pod 的状态。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果描述容器，则可以查看容器的阶段。下面是一个示例。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/1b690997546ceb41acd6764fe3721609.png&quot; alt=&quot;20240722205216.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;如果您想了解更多信息，请查看有关 &lt;a href=&quot;https://devopscube.com/kubernetes-pod-lifecycle/&quot;&gt;Pod 生命周期&lt;/a&gt; 的详细博客。&lt;/p&gt;
&lt;h1&gt;Pod 功能特性&lt;/h1&gt;
&lt;p&gt;我们部署了一个简单的 Nginx pod，配置非常少。但是，Pod 在资源管理、配置、机密、可用性、安全性等方面具有许多功能。&lt;/p&gt;
&lt;p&gt;如果你是初学者，一口气学会所有这些概念就太过分了。在实际用例中使用与 Pod 相关的对象（如部署）时，学习所有这些概念更有意义。&lt;/p&gt;
&lt;p&gt;此外，您需要通过实际用例详细了解每个功能。以下是与容器相关的主要功能。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Resource Requests and Limits: 资源请求和限制：Pod CPU/内存分配&lt;/li&gt;
&lt;li&gt;Labels: 标签：附加到 Pod 的键值对，用于对资源进行分类。&lt;/li&gt;
&lt;li&gt;Selectors: 选择器：根据标签对资源进行分组。&lt;/li&gt;
&lt;li&gt;Liveness, Readiness, and Startup Probes: 存活、就绪和启动探测：容器运行状况检查&lt;/li&gt;
&lt;li&gt;ConfigMaps: 用于配置管理&lt;/li&gt;
&lt;li&gt;Secrets: 用于密钥管理&lt;/li&gt;
&lt;li&gt;Volumes: 卷：持久性数据存储&lt;/li&gt;
&lt;li&gt;Init Containers: 初始化容器：在主容器之前运行的容器。&lt;/li&gt;
&lt;li&gt;Ephemeral Containers: 临时容器：添加到容器中的临时容器，用于调试或故障排除目的。&lt;/li&gt;
&lt;li&gt;Service Account: 服务帐户：限制对 Kubernetes 对象和资源的访问。&lt;/li&gt;
&lt;li&gt;SecurityContext: 主机权限和特权。&lt;/li&gt;
&lt;li&gt;Affinity and Anti-Affinity Rules: 亲和和反亲和规则：跨节点的 Pod 放置控制&lt;/li&gt;
&lt;li&gt;Pod Preemption &amp;amp; Priority: Pod 抢占和优先级：设置 Pod 调度和逐出的优先级。&lt;/li&gt;
&lt;li&gt;Pod Disruption Budget: 容器中断预算：在自愿中断期间需要运行的容器副本的最小数量。&lt;/li&gt;
&lt;li&gt;Container Life Cycle Hooks: 容器生命周期钩子：根据 Pod 的生命周期阶段变化执行自定义脚本。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;全面的 Pod YAML 配置&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：我给出以下示例仅供参考。不要被所有参数所淹没。它并不像看起来那么复杂。一旦你了解了基础知识，就会很容易。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果您添加我上面列出的 pod 功能，您将获得一个全面的 pod YAML 配置，如下所示。此外，这些选项将与 Deployment、Statefulset 等对象一起使用。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apiVersion: v1
kind: Pod
metadata:
  name: web-server-pod
spec:
  initContainers:
  - name: init-myservice
    image: busybox:1.28
    command: [&apos;sh&apos;, &apos;-c&apos;, &apos;echo &quot;Init container started!&quot;&apos;]
  containers:
  - name: web-server
    image: nginx:latest
    ports:
    - containerPort: 80
    volumeMounts:
    - name: shared-data
      mountPath: /usr/share/nginx/html
    - name: secret-volume
      mountPath: /etc/my-secret
    - name: configmap-volume
      mountPath: /etc/config
    securityContext:
      capabilities:
        add: [&quot;NET_ADMIN&quot;, &quot;SYS_TIME&quot;]
    resources:
      requests:
        memory: &quot;64Mi&quot;
        cpu: &quot;250m&quot;
      limits:
        memory: &quot;128Mi&quot;
        cpu: &quot;500m&quot;
    readinessProbe:
      httpGet:
        path: /index.html
        port: 80
      initialDelaySeconds: 5
      periodSeconds: 5
    livenessProbe:
      httpGet:
        path: /index.html
        port: 80
      initialDelaySeconds: 15
      periodSeconds: 20
    startupProbe:
      httpGet:
        path: /index.html
        port: 80
      failureThreshold: 30
      periodSeconds: 10
    lifecycle:
      postStart:
        exec:
          command: [&quot;/bin/sh&quot;, &quot;-c&quot;, &quot;echo &apos;PostStart&apos;&quot;]
      preStop:
        exec:
          command: [&quot;/bin/sh&quot;, &quot;-c&quot;, &quot;echo &apos;PreStop&apos;&quot;]
  serviceAccountName: nginx-service-account   
  securityContext:                        
    runAsUser: 1000
    runAsGroup: 3000
    fsGroup: 2000
  shareProcessNamespace: true
  volumes:
  - name: shared-data
    emptyDir: {}
  - name: secret-volume
    secret:
      secretName: nginx-secret
  - name: configmap-volume
    configMap:
      name: nginx-configmap
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Pod 关联对象&lt;/h1&gt;
&lt;p&gt;在 Kubernetes 上运行应用程序时，我们不会运行单个 pod。因为 Kubernetes 是关于扩展和维护 Pod 的可用性的。因此，如果您运行单个 Pod，它将是单点故障。因为 Pod 本身无法直接缩放。正如我们在 Kubernetes 架构中所讨论的，我们需要像 Replicaset 这样的控制器来确保始终运行所需数量的 Pod。&lt;/p&gt;
&lt;p&gt;Kubernetes 具有与不同用例相关的 Pod 的不同类型的对象。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/83e2a69bd7b70b6cf0bab473ece1acab.gif&quot; alt=&quot;pod-objects.gif&quot; /&gt;&lt;/p&gt;
&lt;p&gt;以下是与 Pod 相关的重要对象。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Replicaset：保持一组稳定的 Pod 副本在任何给定时间运行。&lt;/li&gt;
&lt;li&gt;Deployment: 部署：运行无状态应用程序，如 Web 服务器、API 等&lt;/li&gt;
&lt;li&gt;StatefulSets: 运行有状态应用程序，如分布式数据库。&lt;/li&gt;
&lt;li&gt;Daemonsets: 守护程序集：在所有 Kubernetes 节点上运行代理。&lt;/li&gt;
&lt;li&gt;Jobs: 作业：用于批处理&lt;/li&gt;
&lt;li&gt;CronJobs: 计划作业&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;总结&lt;/h1&gt;
&lt;p&gt;在本指南中，我们了解了 Kubernetes Pod 的所有核心概念。正如我在介绍中提到的，在 kubernetes 生产级实现方面，pod 有很多功能。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;本文翻译自：https://devopscube.com/kubernetes-pod/&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded><author>Derick</author></item><item><title>Energy Management: 10 Common Mistakes to Avoid</title><link>https://blog.ithuo.net/posts/manage-your-energy-not-your-time/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/manage-your-energy-not-your-time/</guid><pubDate>Thu, 13 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;:::note&lt;/p&gt;
&lt;p&gt;If you&apos;re feeling overwhelmed and stressed, you&apos;re not alone. Many people struggle with time and energy management. But the good news is that there are things you can do to improve your situation.&lt;/p&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;p&gt;In today&apos;s fast-paced world, it&apos;s easy to feel overwhelmed and stressed. We&apos;re constantly bombarded with information and demands on our time, and it can be difficult to know how to manage our energy effectively.&lt;/p&gt;
&lt;p&gt;In this blog post, we&apos;ll discuss 10 common mistakes that people make when trying to manage their time and energy. By avoiding these mistakes, you can learn to work smarter, not harder, and achieve your goals with greater ease.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mistake 1: Always waiting to feel &quot;ready&quot; to take action.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;How many times have you had a great idea, but then put it off because you didn&apos;t feel fully prepared? The truth is, you&apos;ll never feel 100% ready to take on a new challenge. The best way to get started is simply to begin. Don&apos;t wait for the perfect moment - it may never come.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mistake 2: Trying to do too much at once.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It&apos;s tempting to try to cram as much as possible into your day, but this is a recipe for burnout. Instead, focus on doing a few things well rather than trying to do everything perfectly. When you&apos;re focused on one task at a time, you&apos;ll be more productive and less likely to make mistakes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mistake 3: Trying to fill every minute of your day.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Some people believe that the more busy they are, the more productive they&apos;re being. However, this is not always the case. In fact, taking breaks throughout the day can actually help you to be more focused and productive when you&apos;re working. Schedule some time each day to relax and recharge, and you&apos;ll be amazed at how much better you feel and work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mistake 4: Thinking that you can work effectively in any environment.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Your environment can have a big impact on your productivity. If you&apos;re constantly surrounded by distractions, it&apos;s going to be difficult to focus on your work. Find a quiet place where you can work without interruption, and you&apos;ll see a big difference in your output.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mistake 5: Believing that plans are worthless because they never go according to schedule.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Of course, plans don&apos;t always go perfectly according to schedule. But that doesn&apos;t mean they&apos;re not worth making. Having a plan can help you to stay on track and make sure that you&apos;re not wasting time on unimportant tasks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mistake 6: Thinking that once you&apos;ve completed a task, you&apos;re done with it.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Just because you&apos;ve finished a task doesn&apos;t mean that you&apos;re done with it for good. It&apos;s important to take some time to review your work and make sure that it&apos;s up to your standards. You may also want to take some time to reflect on what you did well and what you could improve on next time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mistake 7: Believing that time management is just about managing your time.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Time management is not just about squeezing more tasks into your day. It&apos;s also about managing your energy and making sure that you&apos;re using it in the most effective way possible. This means taking breaks when you need them, saying no to requests that you don&apos;t have time for, and delegating tasks when possible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mistake 8: Thinking that it&apos;s enough to just do what your boss tells you to do.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you want to advance your career, you need to take initiative and go above and beyond what&apos;s expected of you. This means taking on new challenges, learning new skills, and always looking for ways to improve your work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mistake 9: Believing that you can overcome procrastination with willpower alone.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Procrastination is a common problem, but it&apos;s not one that you can simply willpower away. There are a number of strategies that you can use to overcome procrastination, such as breaking down large tasks into smaller ones, setting deadlines, and rewarding yourself for completing tasks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mistake 10: Thinking that time management is only about managing your own time.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Time management is also about managing the time of others. This means being respectful of other people&apos;s time, scheduling meetings effectively, and following through on your commitments.&lt;/p&gt;
&lt;p&gt;By avoiding these common mistakes, you can learn to manage your time and energy more effectively. This will help you to be more productive, achieve your goals, and reduce stress.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Additional tips for effective energy management:&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Get enough sleep.&lt;/strong&gt; When you&apos;re well-rested, you&apos;ll have more energy and focus throughout the day.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Eat a healthy diet.&lt;/strong&gt; Eating nutritious foods will give you the energy you need to power through your day.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exercise regularly.&lt;/strong&gt; Exercise is a great way to boost your energy levels and improve your mood.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Take breaks throughout the day.&lt;/strong&gt; Get up and move around every 3&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Derick</author></item><item><title>从翻译Solana文档讨论分布式协作</title><link>https://blog.ithuo.net/posts/team-work-dex/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/team-work-dex/</guid><pubDate>Tue, 28 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;:::note[分布式协作：从 Git Flow 到透明高效的工作方式]&lt;/p&gt;
&lt;p&gt;随着互联网技术的发展，分布式协作已经成为许多团队和组织的首选工作方式。通过分布式协作，团队成员可以跨地域、跨时区高效协同工作，大大提高了工作效率和灵活性。而在软件开发领域，Git Flow 就是一种非常流行的分布式协作工作流。&lt;/p&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;h2&gt;什么是 Git Flow？&lt;/h2&gt;
&lt;p&gt;Git Flow 是一种基于 Git 分支模型的工作流，由 Vincent Driessen 提。它定义了一套规范来管理项目的分支，包括主分支（master）、开发分支（develop）、功能分支（feature）、发布分支（release）和修复分支（hotfix）等。&lt;/p&gt;
&lt;p&gt;通过使用 Git Flow，团队可以更好地组织和管理代码，实现并行开发、持续集成和发布等。例如，开发人员可以在功能分支上独立开发新功能，完成后再合并到开发分支；当需要发布新版本时，可以从开发分支创建发布分支，进行测试和修复，最后合并到主分支并打上版本标签[3]。&lt;/p&gt;
&lt;h2&gt;分布式协作的优点&lt;/h2&gt;
&lt;p&gt;分布式协作有许多优点，包括：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;提高效率&lt;/strong&gt;：团队成员可以并行工作，减少等待时间，提高开发效。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;增强透明度&lt;/strong&gt;：通过 Pull Request（PR）等机制，每个任务的进度都是透明的，便于团队协调和管理。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支持异地协作&lt;/strong&gt;：分布式协作使得团队成员可以在不同地点，甚至不同时区高效协同工作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;加强代码质量&lt;/strong&gt;：通过 Code Review 等流程，可以有效提高代码质量，减少错误和安全隐患。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;分布式协作的挑战&lt;/h2&gt;
&lt;p&gt;尽管分布式协作有诸多优点，但也存在一些挑战：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;沟通成本&lt;/strong&gt;：分布式团队成员难以面对面沟通，可能导致信息传递不畅，需要更多的书面沟通。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文化差异&lt;/strong&gt;：不同地区、不同背景的团队成员可能有文化差异，需要更多地相互理解和包容。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工具和基础设施&lt;/strong&gt;：分布式协作对工具和基础设施有更高的要求，如源码管理、持续集成等，需要投入更多的资源。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;总的来说，分布式协作已经成为许多团队的必然选择。通过采用 Git Flow 等工作流，并配合适当的工具和文化建设，团队可以克服分布式协作的挑战，实现高效、透明、灵活的工作方式，极大地提升工作效率和质量。&lt;/p&gt;
&lt;p&gt;在翻译 Solana 技术文章的过程中，通过 Git Flow 等分布式协作方式，可以让多人协同工作，提高翻译效率和质量。每个文件通过一个 PR 来提交，使得任务进度透明，便于跟踪和管理。这种工作方式值得在更多场景中应用和推广&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>如何有效管理多个 Terraform 环境</title><link>https://blog.ithuo.net/posts/how-to-effectively-manage-multiple-terraform-environments/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/how-to-effectively-manage-multiple-terraform-environments/</guid><pubDate>Wed, 22 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;介绍&lt;/h3&gt;
&lt;p&gt;在这篇文章中，我们讨论使用 &lt;code&gt;Terraform&lt;/code&gt; 管理多个环境的各个方面。通常我们使用 &lt;code&gt;Terraform&lt;/code&gt; 将基础设施定义为代码。然后使用 &lt;code&gt;Terraform CLI&lt;/code&gt;，我们在选择的云平台中创建指定的基础设施组件。&lt;/p&gt;
&lt;h2&gt;多种环境的基础设施&lt;/h2&gt;
&lt;p&gt;下面列出了使用 IaC 管理多个环境的基础设施的普遍期望要求：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;应该可以使用相同的 IaC 配置来管理生产和非生产环境。&lt;/li&gt;
&lt;li&gt;某些非生产环境（例如开发、QA、测试版或 UAT）应该与生产环境相同且缩小版本，并且永久存在。&lt;/li&gt;
&lt;li&gt;团队成员应该能够创建、管理和销毁与生产环境相同的临时环境。&lt;/li&gt;
&lt;li&gt;并非所有环境都在同一云帐户或订阅中创建。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这里的关键之一是对所有环境中的基础设施使用相同的 &lt;code&gt;Terraform&lt;/code&gt; 配置模板。因此，引入对 IaC 的修改没有太大关系，但在这篇文章中，我们将重点讨论如何使用 &lt;code&gt;Terraform&lt;/code&gt; 工作区、&lt;code&gt;Git&lt;/code&gt; 分支和 &lt;code&gt;Spacelift&lt;/code&gt; 堆栈有效管理各种环境。&lt;/p&gt;
&lt;h2&gt;1.Terraform工作区&lt;/h2&gt;
&lt;p&gt;Terraform 提供了工作区功能，使您能够使用相同的配置创建和管理多个相同的、按比例缩小的环境。通过这种方式创建的多个环境是完全隔离的，不会以任何方式相互干扰。这是我们期待的一个关键功能。让我们看看如何利用它。&lt;/p&gt;
&lt;p&gt;Terraform 工作区与 Terraform Cloud 工作区不同。在 Terraform Cloud 中，工作区类似于“项目”，对应于 Terraform 配置存储库。除了存储和管理状态信息之外，它们还管理变量、凭证、历史跟踪等，以支持端到端 Terraform Cloud CI/CD 工作流程。&lt;/p&gt;
&lt;h3&gt;用于使用工作区的 Terraform CLI 命令&lt;/h3&gt;
&lt;p&gt;Terraform 工作区命令的基本用法 - 每个命令都遵循以下简单格式：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;terraform 工作空间 &amp;lt;命令&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;show - 输出当前选定的工作区。始终会选择一个名为“default”的默认工作区。&lt;/li&gt;
&lt;li&gt;list - 输出当前可用于此配置的工作区列表。&lt;/li&gt;
&lt;li&gt;new &amp;lt;name&amp;gt; - 创建具有所需名称的新工作区。&lt;/li&gt;
&lt;li&gt;select &amp;lt;名称&amp;gt; - 选择特定工作区。&lt;/li&gt;
&lt;li&gt;删除&amp;lt;名称&amp;gt; - 删除工作区。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面的 CLI 输出显示了管理工作区的示例。检查当前选定的工作区（默认），然后创建一个名为 beta 的新工作区，列出所有工作区，并删除 beta 工作区。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;% terraform workspace show
default
% terraform workspace new beta
Created and switched to workspace &quot;beta&quot;!

You&apos;re now on a new, empty workspace. Workspaces isolate their state,
so if you run &quot;terraform plan&quot; Terraform will not see any existing state
for this configuration.
% terraform workspace list
  default
* beta

% terraform workspace select default
Switched to workspace &quot;default&quot;.
% terraform workspace delete beta
Releasing state lock. This may take a few moments...
Deleted workspace &quot;beta&quot;!
% terraform workspace list
* default
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;工作空间插值&lt;/h3&gt;
&lt;p&gt;要使用相同的配置管理多个缩小的环境，我们需要一种方法让 Terraform 知道我们正在使用哪个工作区。这有助于正确设置配置。比如，我们可能希望为由特定工作区管理的环境配置更多的 EC2 实例，并为其他环境配置更少的实例。&lt;/p&gt;
&lt;p&gt;Terraform 工作空间插值序列为我们提供了一种实现这种动态变化的方法。通过访问所选工作区的值，我们可以使用多个构造和运算符来创建具有所需规模和其他自定义属性的环境。&lt;/p&gt;
&lt;p&gt;考虑下面的例子。此处，&lt;code&gt;Terraform&lt;/code&gt; 配置旨在在 AWS 中创建 EC2 实例。但是基于所选工作空间的计数属性定义了要创建的实例数量。这里，“&lt;code&gt;terraform.workspace&lt;/code&gt;”插值序列用于访问它。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;resource &quot;aws_instance&quot; &quot;my_vm&quot; {
 count         = terraform.workspace == &quot;default&quot; ? 3 : 1
 ami           = var.ami //Ubuntu AMI
 instance_type = var.instance_type

 tags = {
   Name = format(&quot;%s_%s_%s&quot;, var.name_tag, terraform.workspace, count.index)
 }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果选择“默认”工作区，则将创建三个 EC2 实例，否则仅创建一个。这只是一个例子。我们可以使用更复杂的变量和运算符来管理更多的环境。&lt;/p&gt;
&lt;h3&gt;基础设施和应用程序开发&lt;/h3&gt;
&lt;p&gt;端到端产品开发需要基础设施和要部署在基础设施上的应用程序。通常相应的单独团队负责各自的任务。&lt;/p&gt;
&lt;p&gt;在微服务世界中，由于依赖性和资源限制，在本地计算机上测试和开发应用程序可能并不总是可行。即使在将更改部署到“永久”开发环境之前，应用程序团队成员也可能需要旋转临时环境来运行他们的测试用例。&lt;/p&gt;
&lt;p&gt;在这种情况下，无需担心 &lt;code&gt;Terraform&lt;/code&gt; 源代码，他们可以简单地克隆存储库，然后使用工作区功能创建自己的临时环境。此功能对于应用程序开发团队非常有用，可以在将更改合并到开发并在此处推广之前单独运行其测试用例。&lt;/p&gt;
&lt;h3&gt;帐户和凭据&lt;/h3&gt;
&lt;p&gt;多个环境通常使用多个云帐户或订阅进行管理。云平台还实施“组织”概念，从单个根帐户管理多个帐户。该根帐户负责所有管理活动，例如计费、访问配置等。&lt;/p&gt;
&lt;p&gt;当“应用”Terraform 配置时，将根据目标帐户的提供程序配置验证并执行更改。您可以在下面找到使用共享凭证文件的 AWS Terraform 提供程序配置。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;provider &quot;aws&quot; {
  shared_config_files      = [&quot;/path/to/.aws/conf&quot;]
  shared_credentials_files = [&quot;/path/to/.aws/creds&quot;]
  profile                  = &quot;profile_name&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这里，我们对配置文件名称进行了硬编码，以便 &lt;code&gt;Terraform&lt;/code&gt; 使用目标帐户的适当凭据。在这里，我们还可以利用工作区插值序列从共享凭据文件中动态选择配置文件名称。此外，AWS 还提供了一种在目标账户中担任 IAM 角色的方法。&lt;/p&gt;
&lt;h3&gt;工作空间：优点和缺点&lt;/h3&gt;
&lt;p&gt;当涉及使用 &lt;code&gt;Terraform&lt;/code&gt; 管理多个环境时，&lt;code&gt;Terraform&lt;/code&gt; 中的状态管理可能是一个敏感话题。但是&lt;code&gt;Terraform&lt;/code&gt; 提供的工作区管理通过在当前设置的后端中创建子目录来在幕后处理此问题。&lt;/p&gt;
&lt;p&gt;状态管理也可能是一个限制因素，因为所有状态文件都存储在同一个后端目录中。这意味着用于处理 terraform 配置的所有插件也会在每个工作空间中复制。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Terraform&lt;/code&gt; 工作区提供了一种创建瞬态环境的好方法，只需学习一些命令即可测试基础架构更改。&lt;/p&gt;
&lt;p&gt;依靠内部接线——使用插补序列。如果代码已经构建，引入工作区插值依赖项可能需要花费一些精力。&lt;/p&gt;
&lt;h2&gt;2. Terragrunt&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Terragrunt&lt;/code&gt; 是一个 &lt;code&gt;Terraform&lt;/code&gt; 包装器，旨在填补大规模 &lt;code&gt;Terraform&lt;/code&gt; 配置方面的空白。&lt;/p&gt;
&lt;p&gt;管理云基础设施时，通常会拥有多个环境，例如开发、测试、阶段和生产。这些环境通常具有相似的基础设施，但其变量的配置值不同。 &lt;code&gt;Terragrunt&lt;/code&gt; 通过提供 DRY 配置、处理依赖关系和简化远程状态管理，帮助您有效管理这些多个环境。&lt;/p&gt;
&lt;h3&gt;使用 Terragrunt 进行 DRY 配置&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Terragrunt&lt;/code&gt; 的主要优点之一是它能够保持配置干燥。在处理多个环境时，特定于环境的 Terraform 配置之间通常会存在大量配置重复。&lt;/p&gt;
&lt;p&gt;Terragrunt 通过重用 Terraform 配置解决了这个问题。使用其包含选项，您可以从父 &lt;code&gt;terragrunt.hcl&lt;/code&gt; 文件继承配置，使您能够定义一次通用配置，然后进行特定于环境的覆盖，从而减少重复并最大限度地减少人为错误。&lt;/p&gt;
&lt;h3&gt;依赖管理&lt;/h3&gt;
&lt;p&gt;随着基础设施变得越来越复杂，资源之间的依赖关系变得不可避免。例如，可能需要在依赖数据库的应用程序服务器之前设置数据库。在某些用例中，这些资源是在不同的 Terraform 配置中创建的。 &lt;code&gt;Terragrunt&lt;/code&gt; 的依赖关系块允许您显式地表达这些模块间依赖关系。&lt;/p&gt;
&lt;p&gt;通过这样做，您可以确保按照正确的顺序创建或销毁配置，并尊重依赖关系链。此功能在多环境设置中特别有价值，在多环境设置中，确保跨环境资源配置的正确顺序变得至关重要。&lt;/p&gt;
&lt;h3&gt;简化的远程状态管理&lt;/h3&gt;
&lt;p&gt;特别是在多个环境中，由于手动配置和潜在的不一致，&lt;code&gt;Terraform&lt;/code&gt; 中的远程状态管理可能会成为一项挑战。 &lt;code&gt;Terragrunt&lt;/code&gt; 通过自动为您管理后端配置来简化此过程。它确保每个环境的状态存储在单独的隔离位置（例如，不同的 S3 存储桶路径），从而增强安全性和分离性。这种自动化方法减少了手动开销，并最大限度地降低了与管理各种环境的状态相关的风险。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Terragrunt&lt;/code&gt; 增强了 &lt;code&gt;Terraform&lt;/code&gt; 的功能，特别是对于大规模、多环境基础设施，使环境管理更具可扩展性、可维护性且不易出错。&lt;/p&gt;
&lt;h2&gt;3.Git 分支&lt;/h2&gt;
&lt;p&gt;在本节中，我们将探讨使用 Git 分支来管理多个环境的可能性，并确定为什么它可能不是最佳策略。下图旨在满足本文章简介中所述的要求。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/e80a1861be561b5708b932b547582e23.png%26w%3D3840%26q%3D75&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;发展的两个方面——基础设施和应用——分别以绿色和蓝色突出显示。这里表示的分支策略是使用 Terraform 配置用于各种目的的粗略应用。我们将在讨论 Git 分支的各个部分时进一步探讨这一点。&lt;/p&gt;
&lt;h3&gt;Git 的目的&lt;/h3&gt;
&lt;p&gt;简而言之，Git 旨在协调整个团队的开发工作。它维护各种版本的源代码和部署包版本。主分支通常包含经过充分测试的功能，适用于任何给定软件的一般用途。&lt;/p&gt;
&lt;p&gt;为了执行开发活动或以错误修复、功能或增强形式引入任何更改，将创建主分支的副本，在该副本上执行修改、重建、部署到子生产环境，并在合并之前进行彻底测试对主分支的更改。&lt;/p&gt;
&lt;h3&gt;环境的 Git 分支&lt;/h3&gt;
&lt;p&gt;考虑到这一点，使用 Git 分支来管理多个环境是可能的，而且相当诱人——每个环境一个分支。在给定的图中，基础设施开发团队在三个分支上工作：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;主要 - 用于管理生产基础设施设置。&lt;/li&gt;
&lt;li&gt;QA - 用于管理 QA 基础设施设置，合格的用户在其中执行 UAT 测试。&lt;/li&gt;
&lt;li&gt;Dev - 用于管理开发基础设施设置，其中首先发布功能并进行单元测试。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在较高级别上，从主分支分支并创建相同配置的副本来创建 QA 和开发环境是有意义的。&lt;/p&gt;
&lt;h3&gt;这种方法的问题&lt;/h3&gt;
&lt;p&gt;在源代码级别，这一切都是有意义的。当我们将 Terraform 的更深层次视为 IaC 时，我们需要担心一些关键点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;状态文件管理和关联的远程后端。&lt;/li&gt;
&lt;li&gt;缩放方面转化为特定于环境的属性。&lt;/li&gt;
&lt;li&gt;多个帐户的凭据。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这里考虑的环境是单独的基础设施部署。每个环境自然都有自己的状态信息，需要进行远程安全管理。远程后端在 terraform 资源块中定义。&lt;/p&gt;
&lt;p&gt;下面的示例使用 &lt;code&gt;AWS S3&lt;/code&gt; 后端。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;terraform {
  required_providers {
    aws = {
      source  = &quot;hashicorp/aws&quot;
      version = &quot;~&amp;gt; 4.18.0&quot;
    }
  }

  backend &quot;s3&quot; {
    bucket         = &quot;tf-state-bucket&quot;
    key            = &quot;terraform.tfstate&quot;
    region         = &quot;eu-central-1&quot;
    dynamodb_table = &quot;tf_state_lock&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;假设这是生产环境（即主分支）使用的配置，当我们从主分支分支时，后端配置也会被复制。所有 &lt;code&gt;Terraform CLI&lt;/code&gt; 命令都将假定此后端对于所有其他副本（分支）都是相同的，这是不可取的，并且可能会被证明风险很大。事实上，运行任何 Terraform 命令（例如计划、应用、销毁）都将引用生产状态文件，甚至对生产执行操作。&lt;/p&gt;
&lt;p&gt;如果我们手动修改后端配置以针对 &lt;code&gt;QA&lt;/code&gt; 和开发环境使用不同的后端，则会违背 &lt;code&gt;Git&lt;/code&gt; 的全部目的。 &lt;code&gt;Git&lt;/code&gt; 合并会引发冲突，并要求开发人员通过选择后端之一来解决这些冲突。&lt;/p&gt;
&lt;p&gt;这也适用于 &lt;code&gt;.tfvars&lt;/code&gt; 文件中定义的特定于环境的属性值。各种环境的扩展方面是通过变量进行管理的——更具体地说，是&lt;code&gt;.tfvars&lt;/code&gt; 文件。现代 Git 工作流程通常要求在任何分支之间进行推送和拉取。在这种方法中这可能是不可能的。&lt;/p&gt;
&lt;p&gt;提供商配置可以拥有多个别名来表示多个云提供商帐户和区域中的部署。这也被 Git 的优点所取代。&lt;/p&gt;
&lt;h3&gt;CI/CD 管道&lt;/h3&gt;
&lt;p&gt;大多数远程 Git 存储库（尤其是 &lt;code&gt;GitHub Actions&lt;/code&gt; 和 &lt;code&gt;Gitlab CI/CD&lt;/code&gt;）都提供了以 &lt;code&gt;CI/CD&lt;/code&gt; 管道形式引入自动化的能力。&lt;/p&gt;
&lt;p&gt;就源代码版本控制而言，使用远程 Git 存储库并定义同时处理凭据的自动化管道是有意义的。&lt;/p&gt;
&lt;p&gt;在我们的示例中，如果我们在特定分支上进行提交或批准拉取请求，则可以运行特定于分支的管道，该管道使用特定于环境的凭据将更改应用到正确的目标环境。&lt;/p&gt;
&lt;p&gt;但是即使这些解决了凭据问题，特定于环境的提供程序配置和属性仍然是 Git 工作流程的一部分。这与 &lt;code&gt;Terraform&lt;/code&gt; 期望这些配置用于我们预期更改的方式不一致。CI/CD 管道功能是任何其他 Terraform 工作流程都可以利用的功能。因此，这不会为依赖 Git 分支带来任何特定的优势。&lt;/p&gt;
&lt;h3&gt;应用开发&lt;/h3&gt;
&lt;p&gt;现代应用程序开发基于微服务、容器和函数。取决于各种因素，本地开发环境通常是开发团队遇到的问题。一个简单的例子是，当运行一组相互依赖和其他因素的容器时，开发机器上的可用资源可能不够。&lt;/p&gt;
&lt;p&gt;使用 &lt;code&gt;Terraform&lt;/code&gt; 作为 IaC 确实有助于旋转临时和隔离的环境来为开发人员执行单元测试。还可以从所需的源分支（主分支、QA 或开发分支）创建临时 Git 分支，并创建一个隔离的缩小环境 - 如图中的“Temp2”部署所示。&lt;/p&gt;
&lt;p&gt;此外，如果任何应用程序功能依赖于仍在开发中的特定基础设施组件，应用程序团队可以选择从基础设施开发的“dev”分支进行分支，其中包含预期的更改。它由图中的“Temp1”部署表示。&lt;/p&gt;
&lt;p&gt;应该注意的是，使用 Git 分支策略管理环境取决于正确的分支策略到位的总体假设。例如，应用程序开发团队创建的分支可能不会合并到基础设施开发团队的任何分支中。&lt;/p&gt;
&lt;p&gt;如果 Terraform 有办法知道当前签出了哪个分支，那么采用 Git 分支策略会更有意义。使用 Terraform 工作区时，工作区插值序列提供了这个确切的函数。&lt;/p&gt;
&lt;p&gt;💡您可能还喜欢：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://spacelift.io/blog/github-actions-terraform&quot;&gt;如何使用 GitHub Actions 扩展 Terraform 部署&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://spacelift.io/blog/terraform-automation&quot;&gt;使用 Terraform 自动化基础设施部署&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://spacelift.io/blog/terraform-cloud-pricing&quot;&gt;Terraform 云/企业定价 – 层级概述&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4. Spacelift&lt;/h2&gt;
&lt;p&gt;在生产场景中，我们需要利用 &lt;code&gt;Terraform&lt;/code&gt; 工作区来管理各种环境，并利用 &lt;code&gt;Git&lt;/code&gt; 分支来维护 &lt;code&gt;IaC&lt;/code&gt; 源代码本身。&lt;/p&gt;
&lt;p&gt;然而，正如本文前面所讨论的，使用工作区和分支可能会带来严重的风险。这就是 Spacelift 的用武之地。&lt;code&gt;Spacelift&lt;/code&gt; 提供了一种简化的方法来满足我们的要求，如本文简介中所述。&lt;/p&gt;
&lt;h3&gt;Git 集成&lt;/h3&gt;
&lt;p&gt;借助 &lt;code&gt;Spacelift&lt;/code&gt;，我们可以与 &lt;code&gt;GitHub&lt;/code&gt; 和 &lt;code&gt;Gitlab&lt;/code&gt; 等远程 Git 存储库集成。这允许访问使用分支在“通常”开发流程中开发 Terraform 配置的存储库。我说“通常”是因为我们不必担心上一节中讨论的 Git 分支方法中的挑战。&lt;/p&gt;
&lt;h3&gt;堆栈&lt;/h3&gt;
&lt;p&gt;堆栈是使用 &lt;code&gt;Spacelift&lt;/code&gt; 时最重要的概念之一。 &lt;code&gt;Spacelift&lt;/code&gt; 中的 &lt;code&gt;Stack&lt;/code&gt; 表示基于给定 &lt;code&gt;Terraform&lt;/code&gt; 配置的部署。我们可以通过从集成 Git 后可用的所有存储库中选择合适的 Git 存储库来创建 &lt;code&gt;Stack&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;我们还可以选择选择存储库的所需分支来创建我们的堆栈。在下面的屏幕截图中，我们在 Spacelift 中创建了一个代表生产环境的 Stack。&lt;/p&gt;
&lt;p&gt;所选存储库包含我们要在生产环境中创建的所有基础设施组件的 Terraform 配置。请注意，我们选择了生产环境对应的主分支。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/f73164e662fd09f0880b4f56c96c60ac.png%26w%3D3840%26q%3D75&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;同样，可以通过选择相同的存储库但不同的分支来为我们需要的所有环境创建堆栈。&lt;/p&gt;
&lt;p&gt;例如，下面显示的 &lt;code&gt;Stack&lt;/code&gt; 代表除 &lt;code&gt;Prod&lt;/code&gt; 之外的 &lt;code&gt;Dev&lt;/code&gt; 和 &lt;code&gt;QA&lt;/code&gt; 环境，它们映射到同一 Git 存储库的相应分支。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/d9a5ca0a3be14423218e52c05e505898.png%26w%3D3840%26q%3D75&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;特定分支上的任何新提交或合并拉取请求都将触发 Spacelift 中相应堆栈的部署。这完美地满足了为基础设施团队提供开发体验的需求。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;基础设施开发可以在“dev”分支上进行，反映开发环境的变化。&lt;/li&gt;
&lt;li&gt;当更改在开发上得到确认后，这些更改可以合并到 QA 分支中，该分支最终会将更改部署到 QA 环境中。&lt;/li&gt;
&lt;li&gt;接下来是主分支上的拉取请求，这将反映生产环境的变化。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;使用云集成管理多帐户部署&lt;/h3&gt;
&lt;p&gt;AWS 等云平台可以安全地与 Spacelift 集成，以根据 Terraform 配置执行操作。工作人员需要此访问权限才能对云平台进行适当的 API 调用。就 AWS 而言，Spacelift 云集成采用承担角色策略来提供临时访问。&lt;/p&gt;
&lt;p&gt;配置云集成后，每个堆栈都与这些集成相关联，以便部署针对适当的帐户。&lt;/p&gt;
&lt;p&gt;在下面的截图中，我们配置了所有堆栈使用的单个 AWS 帐户。其实也可以配置更多。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/3184c06cf61e8700a61f191d31915b4e.png%26w%3D3840%26q%3D75&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;下面的截图显示了云集成如何与 &lt;code&gt;Stack&lt;/code&gt; 关联。在本例中，我们的开发环境堆栈当前正在使用上面配置的 AWS 开发集成。同样我们的 QA 和 Prod 堆栈可以配置自己的帐户。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/d90bfef68997644a216a08683cfb8f81.png%26w%3D3840%26q%3D75&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;使用上下文管理扩展&lt;/h3&gt;
&lt;p&gt;每个 &lt;code&gt;Stack&lt;/code&gt; 都有一组 &lt;code&gt;Terraform&lt;/code&gt; 在运行时使用的环境变量。最常见的示例是 &lt;code&gt;AWS&lt;/code&gt; 密钥和访问密钥。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/fbe6af38adec839fc8e2846de7ba4bed.png%26w%3D3840%26q%3D75&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;此外，我们可以定义上下文——一组预定义的环境变量。上下文独立于堆栈。因此可以在多个堆栈中重用它们。在示例中，我们配置了一些预定义的上下文，它们为相应的堆栈提供环境变量。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/5b40655bdff6358e0b8c6d81dd076914.png%26w%3D3840%26q%3D75&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;就缩放方面而言，上下文可以提供重要信息，我们的 Terraform 配置可以创建全尺寸或缩小尺寸的版本。有两种方法可以做到这一点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;提供单个标志值，然后在 &lt;code&gt;Terraform&lt;/code&gt; 代码中解释该值以创建具有适当规模的云组件。&lt;/li&gt;
&lt;li&gt;提供上下文中的所有属性值，然后 &lt;code&gt;Terraform&lt;/code&gt; 代码可以轻松解释这些值以设置适当的缩放属性。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我们将使用第一种方法。在这里，在每个上下文中，我们都为名为“&lt;code&gt;workspace&lt;/code&gt;”的变量指定了环境值。不要将此与 &lt;code&gt;Terraform&lt;/code&gt; 工作区功能混淆。我们可以选择我们选择的任何名称。这里的工作空间变量为 &lt;code&gt;Stacks&lt;/code&gt; 提供上下文，指示正在配置哪个环境。下面的示例显示了如何将生产环境的工作区值设置为“prod”。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/ea176222b734106d7fd36d23b11abc19.png%26w%3D3840%26q%3D75&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;然后Terraform 配置会自动解释该值，并在触发生产堆栈时旋转三个 EC2 实例。对于其余的，它会自动创建一个实例。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;resource &quot;aws_instance&quot; &quot;my_vm&quot; {
  count         = var.workspace == &quot;prod&quot; ? 3 : 1
  ami           = var.ami //Ubuntu AMI
  instance_type = var.instance_type

  tags = {
    Name = format(&quot;%s_%s&quot;, var.name_tag, var.workspace)
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;附加堆栈&lt;/h3&gt;
&lt;p&gt;如前所述，应用程序开发团队可能希望创建自己的隔离环境来测试他们的开发。为了满足这一要求，团队成员可以基于相同的 Git 存储库和他们选择的分支创建自己的堆栈。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/03fb4f49e074d643b9342b8a6f9e042a.png%26w%3D3840%26q%3D75&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;基础设施开发团队可以提供预定义的上下文，以供应用程序开发团队使用。&lt;/p&gt;
&lt;p&gt;在我们的例子中，“我的堆栈”堆栈使用预定义的上下文“功能测试”，这为他们提供了适当的扩展限制，而无需担心 Terraform 代码。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/d213971cb0f65ba7e41ab35e9170bba4.png%26w%3D3840%26q%3D75&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;部署堆栈&lt;/h3&gt;
&lt;p&gt;我们现在已经创建了四个堆栈。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/390e6b78754d0fbc1ccc27807a62bd54.png%26w%3D3840%26q%3D75&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;让我们触发所有这些的部署并查看结果。为了简单起见，我为所有堆栈设置了相同的区域。&lt;/p&gt;
&lt;p&gt;下面的屏幕截图显示了所有运行如何成功完成。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/daffe21b79689b53e8800d6c8bfb538b.png%26w%3D3840%26q%3D75&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;要确认相应的 EC2 实例创建，请参见下面的屏幕截图。堆栈已为产品创建了三个实例，并为 QA、开发和功能各创建了一个实例。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/cd2df153331fb4ee470febf344f3fba1.png%26w%3D3840%26q%3D75&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;查看 &lt;a href=&quot;https://spacelift.io/blog/introducing-stack-dependencies-v2&quot;&gt;Spacelift Stack Dependencies v.2&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;通过本文，我们介绍了&lt;code&gt;Terraform&lt;/code&gt;  结合&lt;code&gt;Spacelift&lt;/code&gt;来管理线上多套环境，并采用一个具体的生产场景来举例说明。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Spacelift&lt;/code&gt;  是一个先进的基础设施即代码（IaC）管理平台，旨在简化和增强跨各种云提供商的基础设施部署和管理。它支持多种 IaC 工具，包括 &lt;code&gt;Terraform&lt;/code&gt;、&lt;code&gt;OpenTofu&lt;/code&gt;、&lt;code&gt;Terragrunt&lt;/code&gt;、&lt;code&gt;CloudFormation&lt;/code&gt;、&lt;code&gt;Kubernetes&lt;/code&gt;、&lt;code&gt;Ansible&lt;/code&gt; 和 &lt;code&gt;Pulumi&lt;/code&gt;，使其成为 DevOps 工程师和平台团队的多功能解决方案。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>思考新的学习方式</title><link>https://blog.ithuo.net/posts/considering-new-learning-methods/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/considering-new-learning-methods/</guid><pubDate>Fri, 17 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;:::note&lt;/p&gt;
&lt;p&gt;学习能力强的人普遍具有非常强的问题拆解能力、信息获取能力、逻辑思考能力。&lt;/p&gt;
&lt;p&gt;这些能力有了 AI 的加持会让你变得更强，但 AI 不会让没有这些能力的人拥有这些能力。&lt;/p&gt;
&lt;p&gt;AI 可以解决你知道自己不知道的问题，但是解决不了你不知道自己不知道的问题。&lt;/p&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;h2&gt;学习的重要性变化&lt;/h2&gt;
&lt;h3&gt;传统学习方式的局限性&lt;/h3&gt;
&lt;p&gt;在传统的学习范式中，记忆（通常是死记硬背）和做题套路占据了重要地位。这种应试教育和教培路线虽然在一定程度上提高了学生的考试成绩，但忽视了真正的知识理解和应用能力。&lt;/p&gt;
&lt;h3&gt;新学习方式的崛起&lt;/h3&gt;
&lt;p&gt;随着&lt;code&gt;AI&lt;/code&gt;时代的发展，一些在旧学习范式中已经存在但未被充分重视的学习方式变得愈发重要。例如，阅读（本质上是预训练）和语言学习（语言塑造思维，语言即是智能的体现）在现代教育中应当得到更多关注。&lt;/p&gt;
&lt;p&gt;此外，旧学习范式中被忽视和缺乏的学习元技能也变得至关重要。这些技能包括以个人知识体系为目标的学习和以元学习为内容的学习。费曼式学习法，即以个人知识体系为中心的终身学习，正是这种新学习方式的典型代表。&lt;/p&gt;
&lt;h3&gt;学习情感层面的重要性&lt;/h3&gt;
&lt;p&gt;最重要的变化在于人类学习的情感层面。内驱力、知识好奇心和情绪耐力在现代学习中变得尤为重要。传统的应试技能培养出的“空心学霸”往往缺乏内驱力和人文素养，这在一些高分学生（如吴谢宇等清北学霸）的悲剧中得到了体现。此外，学生中的抑郁症爆发和自杀现象也反映了情感层面问题的严重性。&lt;/p&gt;
&lt;h3&gt;新技术带来的可能性&lt;/h3&gt;
&lt;p&gt;一些以前不可能实现的学习方式现在变得可能了。例如像 &lt;code&gt;Logseq&lt;/code&gt; 这样的知识管理工具和私人 &lt;code&gt;Wiki&lt;/code&gt; 系统，使得知识管理和个人知识体系的外化变得更加便捷。这也是 &lt;code&gt;GPT&lt;/code&gt; 增强个人认知的前提条件。&lt;/p&gt;
&lt;p&gt;图 1：记忆和应试变得不重要了；元学习/构建个人知识体系的学习能力，情感内驱力变得更重要了；&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/34ce784bd4428ddef775a49571cfcd3a.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;图 2：认知增强，大脑增强成为可能了。10 倍速学习，一人抵10 人，100 人成为可能了；GPT 极大扩大一个人的认知边界和能力边界。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/e21041de3ec9896835aaee87d1f63636.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;图 3：核心的学习闭环，学习的认知层模型。在 GPT 时代，这愈发重要。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/97b7633782d0f8152a69cdb39b1e9076.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>许小年：最重要的自由即制定法律和选择政府的自由</title><link>https://blog.ithuo.net/posts/prof-xu-two-pillars-of-a-free-society/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/prof-xu-two-pillars-of-a-free-society/</guid><pubDate>Sun, 12 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;:::note[记录]&lt;/p&gt;
&lt;p&gt;在母亲节这天，我重读了许老师这篇文章，并且备份记录，以后可能连这样的文字都无法通过审查规则了。&lt;/p&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;p&gt;世界从未像今天这样，如此需要重申自由的意义，如此需要强调对自由的保障。&lt;/p&gt;
&lt;p&gt;——许小年&lt;/p&gt;
&lt;p&gt;重要的自由即制定法律和选择政府的自由&lt;/p&gt;
&lt;p&gt;文 | 许小年&lt;/p&gt;
&lt;p&gt;强势大政府的兴起非但解决不了市场失灵的问题，而且限制个人自由，窒息了经济增长最强劲的发动机——个人的想象力和创造性。政府占用了本来可供民间使用的资源，压缩了个人发挥的空间；政府干预扭曲了民间的激励机制，社会停滞，企业和个人逐渐退化。&lt;/p&gt;
&lt;p&gt;大萧条来临时，人们总是本能地寻求政府庇护。因为人们普遍相信，自由市场存在巨大的不确定性，如果失灵必将导致严重的经济危机。&lt;/p&gt;
&lt;p&gt;然而，却很少有人去思考，导致危机的根源到底是什么？以及赋予政府干预经济更大的权力的最终后果。&lt;/p&gt;
&lt;p&gt;世界从未像今天这样，如此需要重申自由的意义，如此需要强调对自由的保障。&lt;/p&gt;
&lt;p&gt;古代的奴隶被剥夺了自由，在强权的压迫下，忍受屈辱以求生存；今天的人们主动放弃自由，以换取精神主宰所承诺的安全与秩序。&lt;/p&gt;
&lt;p&gt;肉体的奴役是对赤裸裸的暴力无可奈何的服从，精神的奴役则源于盲目的自卑和自卑心理支配下的智识自戕。&lt;/p&gt;
&lt;p&gt;人类社会究竟是在进步、退化，还是变换形式的往复循环？&lt;/p&gt;
&lt;p&gt;古希腊人为个人与城邦的关系争论不休，在当代语境中，古老的命题重新表述为市场与政府的分界，以及自由和管制的冲突。&lt;/p&gt;
&lt;p&gt;2008 年，全球爆发前所未有的金融危机，曾经严密而完整的市场逻辑体系，几乎一夜之间就被摧毁殆尽，沉重地打击了世人对自由的信心。&lt;/p&gt;
&lt;p&gt;人们纷纷抓住激流中的稻草，视政府为逃过世纪之劫的最后方舟。&lt;/p&gt;
&lt;p&gt;美国的凯恩斯主义知识精英和他们的政界朋友利用危机中的恐慌情绪和思想混乱，攻击自由市场，将自己描绘成挽狂澜于既倒的救世主。&lt;/p&gt;
&lt;p&gt;凯恩斯主义诞生于 20 世纪「大萧条」期间，这一学派的核心观点是「市场失灵」，或者更准确地讲，自由市场失灵。他们认为，亚当·斯密称赞的「看不见的手」会给这个世界带来混乱和灾难，而灾难的根源就是市场参与者的非理性冲动，凯恩斯称之为「动物精神」。&lt;/p&gt;
&lt;p&gt;既然市场失灵，就需要理性的力量来恢复秩序。在凯恩斯主义看来，这个理性的力量就是政府。政府动用财政和货币政策，以及监管和行政等微观干预手段，遵循「社会利益」最大化的原则，调节经济运行，指导和管理市场交易，克服市场失灵，甚至还应该劫富济贫，在实现资源更有效配置的同时，保证社会公平。&lt;/p&gt;
&lt;p&gt;然而，任何拯救都是有代价的，政府干预必然限制个人自由，皈依凯恩斯主义意味着用自由换取秩序和正义。&lt;/p&gt;
&lt;p&gt;这交易合算吗？事实证明，这是不平等条约，公众交出部分自由，得到的却是更多的麻烦。&lt;/p&gt;
&lt;p&gt;姑且不论「大萧条」和全球金融危机到底是市场失灵还是政府失灵，看似高明的凯恩斯主义在理论上漏洞百出，在实践中与设计的目标南辕北辙，所谓治世良药给憧憬理想国的人们造成更多而不是更少的伤害，真正的受益者只有以救世主身份行事的政府。&lt;/p&gt;
&lt;p&gt;凯恩斯主义主要有两个根本性错误：&lt;/p&gt;
&lt;p&gt;其一，逻辑原点错了，世界上并不存在「社会利益」。社会由张三、李四、王五等具体的个人组成，每个人都有自己的利益，他们的利益或一致，或冲突。例如当中央银行为控制通货膨胀而加息时，存款利率上升，储蓄者支持，企业则因贷款成本上升而反对，而且高利率会引起股票价格下跌，股民因此遭受损失。又如政府管制产品价格，消费者欢迎，但公司利润下降，损害包括股民在内的企业所有者的利益。任何一项政策都会使一些人受益，另一些人受损，因此，无法定义「社会利益」。&lt;/p&gt;
&lt;p&gt;即使人们的利益一致，也是由于每个人的具体诉求相同，例如财产和人身的安全，而不是因为他们的诉求符合某个绝对的和客观的「社会」标准。&lt;/p&gt;
&lt;p&gt;而且，要使悬在空中的抽象整体利益落地，变为可执行的具体政策，需要找到「社会利益」的代表，即有能动性的个人。凯恩斯主义知识分子于是当仁不让地以社会的代表自居，宣布唯有他们把握了社会发展的方向，唯有他们可充分理解「社会利益」，唯有他们能够设计理想的经济政策和社会改造计划，执行他们治国平天下宏图大略的，就是政府和无所不在的官僚体系。&lt;/p&gt;
&lt;p&gt;经过如此的概念转换，个人组成的社会变成了精英主导的社会，个人自由与个人权利消融在「社会利益」中，变为多余的累赘。&lt;/p&gt;
&lt;p&gt;在更多的场合中，个人自由被视为「社会利益」最大化的障碍，遭到大众的唾弃和极权的压制。&lt;/p&gt;
&lt;p&gt;哈耶克尖锐地指出，强调集体利益的危险就在于它要求权力的高度集中，而权力行使者所铺就的是一条「通往奴役之路」。&lt;/p&gt;
&lt;p&gt;其二，否定市场不完美，假设政府很完美。凯恩斯主义者将「市场失灵」归咎于人的「动物精神」，归咎于市场交易的外部性、市场上的自然垄断、信息不对称、交易成本等市场的「非完美」因素；但当他们建议政府干预时，却有意无意地假设了政府官员的完全理性，假设政府是完美的。凯恩斯经济学假定市场参与者是最大化个人利益的「理性经济人」，但在分析政府官员的行为时，却假设他们最大化「社会利益」。&lt;/p&gt;
&lt;p&gt;对于这个明显的逻辑不一致，凯恩斯主义者讳莫如深。现实世界与凯恩斯主义的完美设想相反，官员追求个人利益而非「社会利益」，他们必然会在制定和执行公共政策的过程中，利用手中的公共权力，公开或隐蔽地为自己谋求好处，例如不顾财政资源的限制，增加福利开支，合法地收买选民。另一类常见的交易是议员通过有利于某些工商集团的立法，以得到这些利益集团的政治捐款。&lt;/p&gt;
&lt;p&gt;在法治薄弱的新兴市场国家，政府高官的家族直接经营商业和企业，如印尼前总统苏哈托家族和菲律宾的马科斯家族，这些家族获得了电信、石油等行业的垄断经营权，利润丰厚的政府合同落入他们以及与他们关系密切的承包商手中。&lt;/p&gt;
&lt;p&gt;在政府官员最大化个人利益的现实情况下，研究市场与政府的分界，新古典经济学的分析框架不再适用，需要采用由布坎南（1986 年诺贝尔经济学奖得主）、图洛克、奥尔森等人发展的「公共选择」理论。&lt;/p&gt;
&lt;p&gt;公共选择学派并不因政客的利欲熏心而否定政府，而是强调对政府的监督与制约，只有在公众和媒体的强有力监督下，只有在制度的有效约束下，政府官员才可能按照公众的意愿制定和执行政策。&lt;/p&gt;
&lt;p&gt;即使监督和制约保证了官员与公众目标的一致性，政府的效率仍有可能低于市场上的自发交易，这是因为官员既无激励，亦无信息办好公众委托的事务。&lt;/p&gt;
&lt;p&gt;无论哪个国家，官僚体系的特点是「不求有功，但求无过」，一些事情做对了，公众认为是应该的，不会有任何奖励；做错了则有可能发生公共舆论危机，并且授同僚以柄，在官场升迁的竞争中处于不利地位。&lt;/p&gt;
&lt;p&gt;另外，官员与企业信息不对等。比如对于企业制造的环境污染，凯恩斯主义者提出可以为减排企业提供财政补贴。显而易见，补贴额应该等于减排成本，但政府并没有企业的成本信息，只能要求企业自报。结果可想而知，企业普遍虚假高报。&lt;/p&gt;
&lt;p&gt;有人也许会问，政府为什么不能查处虚报减排成本的企业呢？政府当然可以这样做，但监督检查也是有成本的，成本有可能高到不值得甚至无法负担的地步，而市场之所以有效，归根结底，就在于人们能够在市场上以更低的成本获取更为准确的信息。&lt;/p&gt;
&lt;p&gt;强势大政府的兴起非但解决不了市场失灵的问题，而且限制个人自由，窒息了经济增长最强劲的发动机——个人的想象力和创造性。政府占用了本来可供民间使用的资源，压缩了个人发挥的空间；政府干预扭曲了民间的激励机制，社会停滞，企业和个人逐渐退化。&lt;/p&gt;
&lt;p&gt;处在政府保护下的企业丧失创新的动力，将资源用于游说和贿赂政府，以便继续享受排斥竞争的行政保护政策；个人则依赖政府的福利开支，不再努力学习和勤奋工作。&lt;/p&gt;
&lt;p&gt;战后英国的萎靡不振，今天欧洲的债务危机和日本经济的持续萧条，又何尝不是政府职能扩大、民间创造力衰退所造成的苦果？&lt;/p&gt;
&lt;p&gt;没有个人的创造就没有经济和文化的繁荣，从电灯、汽车到移动通信，从绘画、诗歌到交响乐，无一不是思想自由驰骋和灵感自由升华的结晶，无一不源于个人的自由梦想和自由发挥。&lt;/p&gt;
&lt;p&gt;爱迪生、福特和乔布斯，米开朗基罗、歌德和贝多芬，在自由创作的环境中，他们得以运用其天才，给我们留下了哲学、科学、艺术与财富，构成我们称之为文明的核心。&lt;/p&gt;
&lt;p&gt;墨守成规的官僚体系可以维持自由所需要的和平与秩序，充当自由的守夜人，却绝不可能替代自由的创造力。&lt;/p&gt;
&lt;p&gt;现代人生而自由不言自明，无需论证，集权专制者恐怕也不得不承认这一点，起码在公开场合也要表示出对个人自由的尊重，那些殿前伺候的大学士只能从后门偷运进反个人自由的迷药。&lt;/p&gt;
&lt;p&gt;虽然甘愿饮药者不乏其人，仔细观察，大多因缺乏自信，或者妒嫉到宁可自残进宫，好借皇上的鸟铳，将头顶上自由飞翔的同类击落在地。&lt;/p&gt;
&lt;p&gt;当然，个人自由不是绝对的，可以加以限制，但必须是自愿的，或者说自由只能让渡而不可剥夺。&lt;/p&gt;
&lt;p&gt;自由人和奴才的根本区别在于，前者为了获得更大的自由而自我限制自由，后者则以自我奴役换取奴役他人的权力。&lt;/p&gt;
&lt;p&gt;自我限制的方式是制定法律和规则，法律看上去限制了个人的行动自由，但若没有法律就没有和平秩序，在暴力横行和弱肉强食的世界里，哪里有个人自由可言？法律因此是平等的自由人之间形成的游戏规则，服从法律并非放弃自由，因为法律是他们自己制定的。&lt;/p&gt;
&lt;p&gt;同样的，政府如同法律是保障自由的工具。自由人选择政府，在允许政府使用强制性手段的同时，严格地限定强制性手段的使用范围和使用程序。&lt;/p&gt;
&lt;p&gt;对于现代人，最重要的自由即制定法律和选择政府的自由，这一自由使他们能够享受经济、社会、文化、思想等方面的广泛自由。&lt;/p&gt;
&lt;p&gt;正是在这个意义上，我们说，自由既是目的，又是手段。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>以太坊残酷共学计划</title><link>https://blog.ithuo.net/posts/ethereum-intensive-study/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/ethereum-intensive-study/</guid><pubDate>Sat, 11 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在论坛了解到Bruce发起的新活动，感觉很有意思，对以太坊的各种协议还是很模糊的理解，通过加入到残酷共学活动，在5周的时间内对以太坊的架构，演化过程，执行层，验证层，操作节点都加深了理解，还有在演化过程中更新的协议，可以按照路线看到一个庞大的区块链为了降低交易费用，提升用户体验做出的更新。&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;DerickIT/intensive-ethereum-protocol-study-group&quot;}&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;:::note[共学笔记]
下面是我参加本次共学产生的笔记
:::&lt;/p&gt;
&lt;h1&gt;Derick&lt;/h1&gt;
&lt;p&gt;hi guys， my name is Derick and I&apos;m a back-end programmer who loves technology. I&apos;m looking forward to learning about the Ethereum Protocol by attending https://epf.wiki/&lt;/p&gt;
&lt;h2&gt;Notes&lt;/h2&gt;
&lt;h3&gt;2024.5.10&lt;/h3&gt;
&lt;h4&gt;Capital and enclosure in software commons: Linux &amp;amp; Ethereum&lt;/h4&gt;
&lt;p&gt;这篇&lt;a href=&quot;https://trent.mirror.xyz/GDDRqetgglGR5IYK1uTXxLalwIH6pBF9nulmY9zarUw&quot;&gt;文章&lt;/a&gt;讨论了软件公共资源(如Linux和以太坊)的资本和围栏问题。主要观点如下:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;软件(如Linux和以太坊)是一种共生资源:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;读取状态和历史记录具有低排他性和反竞争性:使用和引用EVM基础设施的人越多,对单个用户的价值就越大。任何运行节点的人都可以通过运行自己的节点来访问。链上数据可称为&quot;知识共享资源&quot;,记录可供任何人验证,是一个广泛可用的丰富数据集。&lt;/li&gt;
&lt;li&gt;写入状态具有低排他性和高竞争性:并发用户数量受区块gas限制的限制,以确保节点运营商的资源需求不会增长太快。尽管它是一个数字对象,但需要注意存储、带宽、计算等方面的限制。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;资本会寻求从哪里提取私人利益,如从状态验证(浏览器)、区块空间生产(MEV、托管验证)和区块空间消费(用户体验、产品)中插入和提取利润。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;文章提出了两个问题:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;嵌入在资源生产中的本地资本形式是否能更好地修改负面外部性?&lt;/li&gt;
&lt;li&gt;随着时间的推移,它是否会加强外部资本进入和吸收资源生产系统的动机?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2024.5.9&lt;/h3&gt;
&lt;h4&gt;SSF带来的问题&lt;/h4&gt;
&lt;p&gt;通过学习&lt;a href=&quot;https://ethresear.ch/t/reorg-resilience-and-security-in-post-ssf-lmd-ghost/14164/3&quot;&gt;这篇文章&lt;/a&gt;，它讨论了以太坊共识协议 LMD-GHOST 在实现单时隙确定性（Single Slot Finality，SSF）后的重组弹性和安全性问题。主要观点如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;当前的 LMD-GHOST 协议在 SSF 设置下存在重组问题，这主要是由于协议考虑了所有的最新消息（Latest Message），而不仅仅是最近的消息。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;为了解决这个问题，作者提出了一种改进的协议，称为 RLMD-GHOST（Recent LMD-GHOST），它只考虑最近 η 个时隙内的最新消息。当 η = 1 时，RLMD-GHOST 退化为 Goldfish 协议；当 η = ∞ 时，它退化为原始的 LMD-GHOST。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;RLMD-GHOST 在一个广义的 sleepy 模型下是动态可用的和重组弹性的。这比通常的 sleepy 模型下的安全性要弱，因为作者对攻击者施加了一些额外的限制，不允许完全可变的参与度。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;尽管如此，作者认为这些假设在实践中是相当合理的。通过适当地选择 η 值，RLMD-GHOST 可以在重组弹性和活性之间取得平衡。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;作者还讨论了 RLMD-GHOST 与 Gasper 的交互，Gasper 是以太坊当前的混合共识协议。他们提出RLMD-GHOST 可以作为 Gasper 的基础层，提供一个可用和重组弹性的链，而 Casper FFG 可以在其上实现经济确定性。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;2024.5.8&lt;/h3&gt;
&lt;h4&gt;MAX_EFFECTIVE_BALANCE提案&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://ethresear.ch/t/increase-the-max-effective-balance-a-modest-proposal/15801&quot;&gt;这篇提案&lt;/a&gt; 提出了一个适度增加以太坊验证者最大有效余额(MAX_EFFECTIVE_BALANCE)的建议,主要内容总结如下:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;目前以太坊的MAX_EFFECTIVE_BALANCE被设置为32 ETH,这导致验证者集合规模非常庞大,截至2023年6月6日已有超过60万个活跃验证者,另有9万个在激活队列中。虽然大量验证者意味着更高的去中心化,但人为限制了验证者的最大规模。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提案建议将MAX_EFFECTIVE_BALANCE从32 ETH提高到更高的值,以鼓励验证者集合收缩,这有利于改善以太坊的可扩展性和降低共识层的复杂性。但同时要保持激活新验证者所需的最低ETH数量不变,以维持去中心化。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;增加MAX_EFFECTIVE_BALANCE可以让大型质押者获得更高的资本效率,因为他们可以更快地提高有效余额,减少提款和重新激活的需求。但也有观点认为,过高的罚没风险可能会阻碍验证者合并。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;有效余额目前以1 ETH为增量单位,并与实际余额分开计算。调整增量单位可能会影响验证者集合的再散列频率,需要进一步研究其复杂性影响。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;2024.5.7&lt;/h3&gt;
&lt;h4&gt;Single-slot finality (SSF)&lt;/h4&gt;
&lt;p&gt;Single-slot finality (SSF) 是以太坊共识机制升级的一个重要目标,旨在将区块达成不可逆的时间从目前的64-95个时隙(约15分钟)缩短到一个时隙(12秒)。&lt;/p&gt;
&lt;p&gt;目前以太坊采用的Gasper共识协议在终局性时间、去中心化程度和链上负载之间做出了折中。而SSF的实现将带来以下好处:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;大幅缩短交易确认时间,提升用户体验&lt;/li&gt;
&lt;li&gt;消除短程重组(short-range reorg)的风险,提高安全性&lt;/li&gt;
&lt;li&gt;简化共识协议,减少潜在的漏洞&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;为实现SSF,以太坊需要减少参与共识的验证者数量,可能的方案包括:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;提高每个验证者的最大质押额度(如从32 ETH提高到2048 ETH),鼓励验证者合并质押&lt;/li&gt;
&lt;li&gt;动态调整验证者的奖励和惩罚,控制总数在一定范围内&lt;/li&gt;
&lt;li&gt;引入超级委员会(supercommittee)机制,由部分验证者代表全体进行共识&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;2024.5.6&lt;/h3&gt;
&lt;h4&gt;view-merge提案&lt;/h4&gt;
&lt;p&gt;以太坊共识层的一个改进提案,称为&lt;a href=&quot;https://ethresear.ch/t/view-merge-as-a-replacement-for-proposer-boost/13739&quot;&gt;view-merge&lt;/a&gt;,旨在取代目前的proposer boost机制。主要观点如下:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;View-merge的核心思想是让区块提议者将真实的验证者签名聚合并引用到区块中,而不是人为地提升某些区块的权重。这样可以避免proposer boost被滥用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;诚实的验证者只会在上一时段提交聚合签名,因此区块提议者通常只需引用上一时段的聚合签名即可。恶意聚合签名占用的空间有上限。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;View-merge消息中只包含对聚合签名的引用以及聚合者作恶的证据,数据量较小。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提议者可以按照时段顺序引用聚合签名,直到达到区块大小上限。超过14个时段以前的签名通常是无关紧要的,除非存在一条很长的竞争分叉。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;未来view-merge机制有望直接整合到区块内容中,而不是单独的消息。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;view-merge提供了一种相对简洁且难以被滥用的机制,在一定程度上可以替代现有的proposer boost,改善以太坊共识的安全性和活性。&lt;/p&gt;
&lt;h3&gt;2024.5.5&lt;/h3&gt;
&lt;h4&gt;PoS演化过程&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;今天学习week 10 research 的&lt;a href=&quot;https://github.com/ethereum/pos-evolution/blob/master/pos-evolution.md&quot;&gt;pos演化过程分析&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这篇文章主要介绍了以太坊从工作量证明(PoW)向权益证明(PoS)共识机制演进的过程和相关技术细节。&lt;/p&gt;
&lt;p&gt;以太坊最初采用PoW共识,但一直计划过渡到PoS。PoS下,区块生产者(验证者)运行全节点,质押原生代币,并根据选择过程提议或验证区块。&lt;/p&gt;
&lt;p&gt;2022年9月,以太坊通过&quot;合并&quot;升级实现了向PoS的转变。合并将原有的执行层与新的PoS共识层(信标链)连接在一起。这要求全节点同时运行执行客户端和共识客户端,两者通过API交互构成完整的以太坊节点。&lt;/p&gt;
&lt;p&gt;合并带来几个主要好处:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;大幅降低能耗,更加环保&lt;/li&gt;
&lt;li&gt;通过质押ETH参与共识,使网络更加去中心化&lt;/li&gt;
&lt;li&gt;为未来分片扩容奠定基础&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;文档还详细介绍了信标链区块的数据结构、验证者的有效余额计算方法等技术实现细节。&lt;/p&gt;
&lt;p&gt;在信标链中,每个区块包含以下关键数据:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;区块头:包含父区块哈希、状态根、签名等元数据&lt;/li&gt;
&lt;li&gt;执行负载:包含已执行交易的相关信息&lt;/li&gt;
&lt;li&gt;共识负载:包含Casper FFG和LMD GHOST共识所需数据,如Epoch号、验证者投票等&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;验证者的有效余额(effective balance)是参与共识的关键因素,但为了性能考虑,有效余额的更新频率远低于实际余额。有效余额具有以下特点:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;有效余额以ETH为单位,必须是EFFECTIVE_BALANCE_INCREMENT常量(即1 ETH)的整数倍,而实际余额以Gwei为单位。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;有效余额设置上限为32 ETH,超出部分不计入有效余额。这促使大户创建多个验证者账户,而不是单个账户质押过多ETH。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;有效余额的调整具有滞后性(hysteresis)。仅当实际余额达到特定阈值时,有效余额才会更新。这避免了频繁重新计算验证者列表的哈希值。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;验证者的出块概率、投票权重、奖惩金额等,都与其有效余额成正比。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;有效余额作为验证者参与共识的加权因子,在性能和经济激励方面达成了平衡。通过限额和滞后调整,在降低计算开销的同时,确保了共识安全和网络去中心化。&lt;/p&gt;
&lt;h3&gt;2024.5.4&lt;/h3&gt;
&lt;h4&gt;Hyperledger Besu&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;通过week 10 dev的课外内容了解到Hyperledger Besu，做私有化，联盟链的时候可以使用。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=djL5nczlYFw&quot;&gt;Hyperledger Besu&lt;/a&gt;是一个专为企业设计的以太坊客户端,旨在满足公共和私有许可网络的需求,具有可提取的以太坊虚拟机(EVM)实现。其主要目的包括:&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;提供一个企业友好的以太坊解决方案:Besu专为企业级用例而设计,支持公共和私有许可网络,满足企业对安全性、隐私性和性能的要求。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;支持多种共识算法:Besu内置了多种共识机制,包括权益证明(PoS)、工作量证明(PoW)以及权威证明(PoA),如IBFT 2.0、QBFT和Clique,适应不同的使用场景。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提供全面的权限管理:Besu提供了专门用于联盟环境的综合权限管理方案,可以精细控制数据访问。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;实现互操作性:Besu不仅可以构建私有网络,还与以太坊网络兼容,具有很强的互操作性。它完全支持流行的ERC721、ERC1155和ERC1400等标准。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;构建去中心化应用:Besu可用于开发各种去中心化应用,如供应链追踪、金融结算、中央银行数字货币(CBDC)、贸易融资等。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Hyperledger Besu旨在为企业提供一个安全、灵活、高性能的以太坊平台,支持构建满足企业级需求的公共和私有许可区块链网络及应用。其开源性质和活跃的社区也为Besu的持续发展和创新提供了动力。&lt;/p&gt;
&lt;h3&gt;2024.5.3&lt;/h3&gt;
&lt;h4&gt;预编译合约的使用方式&lt;/h4&gt;
&lt;p&gt;EVM 预编译合约的使用方式主要包括：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;通过特定地址调用：预编译合约位于 EVM 中从 0x1 到 0x9 的特定地址。可以像调用普通合约一样，使用 CALL 等 EVM 操作码调用这些地址，执行预编译合约。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在 Solidity 中调用：Solidity 提供了一些内置的函数，如 ecrecover、sha256 等，可以直接在 Solidity 代码中调用这些函数，底层实际执行的是对应的预编译合约。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用 Solidity assembly 调用：可以在 Solidity 的 assembly 块中，使用 CALL 操作码直接调用预编译合约的地址。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;设置合适的 gas：调用预编译合约需要提供足够的 gas。每个预编译合约都有特定的 gas 消耗，调用时需要设置合适的 gas limit。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;传入正确的输入：每个预编译合约都有自己的输入格式规范，调用时需要按照规范传入正确的参数。例如，ecrecover 预编译合约需要传入签名的哈希值、v/r/s 值等。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;处理返回值：预编译合约的执行结果会通过返回值返回。调用者需要按照预编译合约的规范，正确解析返回值。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在 L2 上使用自定义预编译合约：一些 L2 如 Bitfinity 支持添加自定义的预编译合约。开发者可以在这些 L2 上部署和使用自己的预编译合约，来实现特定功能。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;使用 EVM 预编译合约主要是通过特定地址调用，并正确设置 gas、传入参数、处理返回值。在 Solidity 中，有一些内置的函数可以直接使用。L2 上还可能支持自定义预编译合约的部署和使用。&lt;/p&gt;
&lt;h3&gt;2024.5.02&lt;/h3&gt;
&lt;h4&gt;预编译智能合约precompiled contracts&lt;/h4&gt;
&lt;p&gt;预编译合约是以太坊提供的一组高度优化的原生函数,主要用于密码学功能。它们位于从0x1到0x8的特定地址。一些主要的预编译合约包括:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;0x1: ECDSA 签名恢复函数(ecrecover)&lt;/li&gt;
&lt;li&gt;0x2: SHA-256 哈希函数(sha256)&lt;/li&gt;
&lt;li&gt;0x3: RIPEMD-160哈希函数(ripemd160)&lt;/li&gt;
&lt;li&gt;0x4: 身份函数(identity)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在以太坊的Go语言客户端实现geth中,预编译合约被定义在一个映射中。Solidity作为以太坊的原生语言,大部分预编译合约的功能都可以通过内置函数直接使用。&lt;/p&gt;
&lt;p&gt;在使用预编译合约时需要注意一些安全问题:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;签名恢复的错误实现可能导致签名延展性问题,攻击者可以操纵签名中的v值生成不同的公钥。&lt;/li&gt;
&lt;li&gt;调用预编译合约需要消耗gas,错误估计gas消耗可能导致out-of-gas异常和交易失败。&lt;/li&gt;
&lt;li&gt;不能假设预编译合约的输出一定是确定性的。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;预编译合约为以太坊提供了高效的密码学原语,开发者可以方便地在智能合约中使用它们,但同时也要注意相关的安全问题。&lt;/p&gt;
&lt;h3&gt;2024.5.01&lt;/h3&gt;
&lt;h4&gt;state_expiry_eip提案&lt;/h4&gt;
&lt;p&gt;这篇&lt;a href=&quot;https://notes.ethereum.org/%40vbuterin/verkle_and_state_expiry_proposal&quot;&gt;提案&lt;/a&gt;是Vitalik Buterin提出的以太坊改进提案(EIP),主要内容是引入状态过期(State Expiry)机制。&lt;/p&gt;
&lt;p&gt;具体来说,该提案建议用一个状态树列表取代单一的状态树,每个树对应大约一年的时间段。状态编辑存储在当前时期对应的树中,超过最近两个时期的树不再由客户端存储。&lt;/p&gt;
&lt;p&gt;使用旧状态(在最近两个时期未被修改)的交易,需要提供证人(witness)。假设已经实施了Verkle树,因此状态对象包含一个Patricia树和一个Verkle树。&lt;/p&gt;
&lt;p&gt;该EIP通过将状态列表扩展为N个Verkle树来实现状态过期,客户端只存储最后两棵树。旧状态仍然可以访问,但交易发送者需要提供证人来验证状态。&lt;/p&gt;
&lt;p&gt;提案还引入了一种新的交易类型SignedNewTransaction,包含了访问旧状态所需的Verkle证明等字段。&lt;/p&gt;
&lt;p&gt;为了支持状态过期(State Expiry)机制,引入了一种新的交易类型SignedNewTransaction。它包含以下字段:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class SignedNewTransaction(Container):
    payload: NewTransaction 
    old_state_proof: VerkleProof
    signature: ECDSASignature

class NewTransaction(Container):
    nonce: uint64
    target_address_period: uint24
    gas: uint64 
    priority_fee: uint64
    max_gasprice: uint64
    to: Address32
    value: uint256 
    data: bytes
    claimed_states: List[StateClaim, 224]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中最关键的是old_state_proof字段,它是一个VerkleProof类型,包含了访问过期状态所需的Verkle树证明。&lt;/p&gt;
&lt;p&gt;由于实施了状态过期后,超过最近两个时期(每个时期约一年)的状态不再由客户端存储,因此如果一个交易需要访问这些旧状态,就必须在交易中附上相应的Verkle证明,证明这些状态在过期之前的存在性和正确性。&lt;/p&gt;
&lt;p&gt;claimed_states字段则列出了该交易声称的一组账户状态。&lt;/p&gt;
&lt;p&gt;其他字段如nonce、gas、to、value、data等与普通交易类似,用于指定交易的各种参数。&lt;/p&gt;
&lt;p&gt;SignedNewTransaction通过引入old_state_proof等字段,使得在状态过期后,交易仍然能够安全地访问和使用旧状态,从而确保了状态过期机制的可行性。这是以太坊在不牺牲去中心化和安全性的前提下,努力提高可扩展性的重要探索之一。&lt;/p&gt;
&lt;h3&gt;2024.4.30&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;学习两个提案并总结内容&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;eip-4444提案&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://eips.ethereum.org/EIPS/eip-4444&quot;&gt;EIP-4444&lt;/a&gt; 提议以下改变以减少以太坊全节点所需的存储空间：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;客户端必须停止在P2P层提供超过1年历史的区块头、区块体和收据数据。客户端可以在本地修剪这些历史数据。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;这将把全节点所需的磁盘空间从目前400GB以上减少到大约60GB。历史数据对验证新区块不是必需的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;这个改变会影响依赖历史数据的应用，如显示区块、交易、账户历史的Web3应用。保存以太坊历史数据仍然很重要，可以通过BT、IPFS等带外方式实现。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;风险是更多应用会依赖中心化服务获取历史数据，因为运行全节点会更困难。独立组织应该定期保存和检查历史数据的可用性。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;这个提案与其他一些提案(如EIP-4488)没有直接关系，可以独立实施。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果通过，建议在上海升级激活，给节点运营者和基础设施提供商至少6个月时间适应改变。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;eip-7668提案&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://eips.ethereum.org/EIPS/eip-7668&quot;&gt;EIP-7668&lt;/a&gt;提议从以太坊执行层区块中移除布隆过滤器(Bloom filters)：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;要求执行区块中的布隆过滤器为空，包括顶层和收据对象中的布隆过滤器。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;最初引入日志(logs)是为了让应用记录链上事件信息，去中心化应用(dapps)可以方便地查询。使用布隆过滤器，dapps可以快速遍历历史，识别包含相关日志的区块，然后快速找到需要的日志。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;但实际上，这种机制太慢了。几乎所有访问历史数据的dapps最终都不是通过对以太坊节点的RPC调用，而是通过中心化的链外索引服务。该提案建议承认这一现实，从协议中删除布隆过滤器。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;需要历史查询的应用应该开发和使用去中心化协议，使用zk-SNARK和可增量验证计算等技术创建可证明的日志索引。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;规范：执行区块的logs bloom现在必须为空(即0字节长)。交易收据的logs bloom现在也必须为空。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;这是一种以最小破坏性的方式消除客户端处理布隆过滤器的需求。未来的EIP可以通过删除该字段以及其他已弃用的字段来进一步清理。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;LOG操作码的gas成本不会降低，因为虽然污染布隆过滤器的外部性不再需要考虑，但由于zk-SNARK EVM实现的需要，哈希的成本已经增加。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;总之，该提案旨在从以太坊执行层移除布隆过滤器，鼓励应用开发去中心化的历史数据索引方案，而不是依赖中心化服务。&lt;/p&gt;
&lt;h3&gt;2024.4.29&lt;/h3&gt;
&lt;h4&gt;Portal Network&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.ethportal.net/overview&quot;&gt;Portal Network&lt;/a&gt; 是一个去中心化的以太坊存档节点API访问网络，它能以近乎零的同步时间和最小的硬件要求为用户提供以太坊数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;传统上，以太坊用户只有两个选择:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;投入大量计算资源和带宽来运行自己的以太坊节点&lt;/li&gt;
&lt;li&gt;信任中心化的第三方(如RPC提供商)来提供以太坊数据&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Portal Network 引入了第三种选择:以最小的硬件和带宽要求，以去中心化的方式访问以太坊数据。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Portal Network 实际上由几个对等网络(状态网络、信标网络和历史网络)组成，可以使用Portal Network客户端访问。每个网络存储以太坊全节点存储的数据的特定子集。每个Portal客户端只存储一小部分每种类型的数据。但Portal Network(完整的节点集)存储从创世块到接近链头的所有历史以太坊数据。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当你向以太坊节点请求数据时，你是在本地区块链副本中查找特定信息。如果通过RPC提供商请求数据，则在其他人存储的区块链副本中查找(他们在处理请求和响应时可能会操纵数据或跟踪你)。同步以太坊全节点需要下载数百GB的历史和状态数据，对其进行验证并在本地存储。这需要节点运营者投入大量CPU、网络带宽(每月1TB)、硬盘存储(1+TB SSD)和内存来运行节点。这使得许多人不愿意完全参与网络，形成了中心化力量，将用户推向第三方。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Portal Network 通过分布式存储以太坊数据，允许用户以最小的硬件和带宽要求，近乎即时的同步速度，以去中心化的方式访问链上数据，从而解决了以太坊节点运营的门槛问题。这有望推动更多用户参与以太坊网络。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2024.4.28&lt;/h3&gt;
&lt;h4&gt;Kurtosis 工具&lt;/h4&gt;
&lt;p&gt;学习week 9 dev 过程中，了解到&lt;a href=&quot;https://github.com/kurtosis-tech/kurtosis&quot;&gt;Kurtosis&lt;/a&gt; 工具，了解了它的功能和优势。&lt;/p&gt;
&lt;p&gt;Kurtosis 是一个用于打包和启动后端技术栈的平台，主要目标是让普通开发者也能轻松上手。它主要包含两个部分:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;一个用于分发后端技术栈定义的打包系统，可以在 Docker 或 Kubernetes 上运行。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一个带有每个技术栈文件管理系统的运行时环境。开发者可以专注于开发，而不用操心复杂的环境配置。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;使用 Kurtosis 的主要优势在于:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;可以轻松创建短暂的开发或测试环境，不用被环境配置等琐事困扰。这在协作开发或为开源项目做贡献时尤其有用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提供了一套标准化的方式来打包、分发和运行后端技术栈，简化了环境管理。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;内置文件管理功能，开发者不必单独搭建文件服务器。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;支持在 Docker 和 Kubernetes 等主流容器平台上运行，兼容性好。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2024.4.27&lt;/h3&gt;
&lt;h4&gt;Attacknet介绍&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Attacknet是一个用于在以太坊上进行混沌工程测试的软件。允许模拟各种边缘情况测试场景，以太坊Dencun分叉升级和peerDAS研究都使用了该工具进行测试。Attacknet的下一步工作重点是实现自动化测试，无需人工监督即可运行。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Attacknet支持配置多种类型的故障，包括网络延迟、抖动、丢包、数据包损坏、带宽限制、网络分割与重新加入、时钟偏差(如NTP故障)、CPU负载、RAM负载，以及磁盘故障、磁盘访问延迟、I/O错误、服务崩溃(即kill)等。目前正在开发的还有内核故障功能。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;文章列举了一些初步计划的测试方案，主要围绕以下三个变量:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;网络中客户端组合&lt;/li&gt;
&lt;li&gt;混沌故障类型&lt;/li&gt;
&lt;li&gt;混沌故障参数&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;测试目标包括分析在不同网络延迟、丢包率、时钟偏差等故障情况下，错过的区块数量，并找出其相关性。测试计划对每种执行层(EL)和共识层(CL)的组合进行重复测试。&lt;/p&gt;
&lt;p&gt;Attacknet的工作原理如下:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;使用Kurtosis生成一个开发网络(devnet)环境，可以创建各种网络拓扑结构。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过Chaos Mesh在devnet中注入各种故障，如网络延迟、丢包、时钟偏差、节点崩溃等，将区块链网络推向极端边缘情况。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;故障结束后，Attacknet对网络中的每个节点执行一系列健康检查，以验证它们是否能从故障中恢复。如果所有节点都恢复了，就转移到下一个配置的故障。如果有节点未通过健康检查，则生成日志和测试信息的构件以进行调试。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Attacknet支持手动配置网络拓扑和故障参数的模式，以及针对特定客户端运行一系列故障的&quot;计划模式&quot;。未来还计划增加一个&quot;探索模式&quot;，动态定义故障参数并反复注入监控网络健康状况，类似于模糊测试。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Attacknet目前正用于测试Dencun硬分叉，并在不断更新以提高覆盖率、性能和调试体验。它不是以太坊特有的工具，而是模块化设计，可轻松扩展以支持其他类型的区块链。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;2024.4.26&lt;/h3&gt;
&lt;h4&gt;以太坊协议升级的测试和原型开发过程&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;通过学习week 9 dev 了解了以太坊协议升级需要经历的测试和原型开发过程。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;开发网络(Devnets):&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;以太坊基础层的测试镜像，包含执行层、共识层和验证者&lt;/li&gt;
&lt;li&gt;允许开发者部署分叉和变更而不影响主网&lt;/li&gt;
&lt;li&gt;完全可控的验证者集合，可设计边缘情况场景进行测试&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;本地测试:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;使用Kurtosis工具进行本地devnet测试，通过YAML文件配置参数&lt;/li&gt;
&lt;li&gt;可快速测试变更，支持异步开发新特性&lt;/li&gt;
&lt;li&gt;可配置参数如时隙时间、快速分叉、MEV工作流等&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;原型测试:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Kurtosis允许覆盖修改网络中的任何内容&lt;/li&gt;
&lt;li&gt;通过替换客户端镜像来测试协议变更&lt;/li&gt;
&lt;li&gt;在现有网络上运行并连接新工具进行测试&lt;/li&gt;
&lt;li&gt;通过修改网络参数来测试快速分叉&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;公共测试网:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;将基础逻辑移至通用Ansible roles中&lt;/li&gt;
&lt;li&gt;将通用组件抽取为独立工具，如创世区块生成器&lt;/li&gt;
&lt;li&gt;使用GitOps使工具独立于仓库/测试网&lt;/li&gt;
&lt;li&gt;统一所有测试网的配置&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;影子分叉(Shadowforks):&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;在整个生命周期内检查所有客户端的兼容性&lt;/li&gt;
&lt;li&gt;全新测试网可以轻松测试不同客户端组合&lt;/li&gt;
&lt;li&gt;影子分叉在真实状态和交易负载下压测客户端&lt;/li&gt;
&lt;li&gt;可控地邀请参与者参与测试&lt;/li&gt;
&lt;li&gt;在向公众推荐新版本前，充当真实世界边缘情况的发布测试&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;其他有用工具:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Assertoor: 断言网络级别的预期行为&lt;/li&gt;
&lt;li&gt;Forky: 以太坊分叉选择可视化工具&lt;/li&gt;
&lt;li&gt;Tracoor: 以太坊交易追踪浏览器&lt;/li&gt;
&lt;li&gt;Dora: 轻量级信标链时隙浏览器&lt;/li&gt;
&lt;li&gt;Xatu: 以太坊P2P层可见性分析工具&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2024.4.25&lt;/h3&gt;
&lt;h4&gt;ePBS flavors&lt;/h4&gt;
&lt;p&gt;Ethereum 目前有两种主要的 PBS (Proposer-Builder Separation) 方案，旨在提高网络的去中心化和安全性:&lt;/p&gt;
&lt;h2&gt;1. 中继者/建造者分离 (Relayer/Builder Separation， 简称 RBS)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;在RBS模型中，区块提议者(proposer)和区块构建者(builder)的角色被分离。&lt;/li&gt;
&lt;li&gt;中继者(relayer)从建造者那里收集区块，并将其转发给提议者。提议者然后选择一个区块，对其进行验证并将其添加到区块链中。&lt;/li&gt;
&lt;li&gt;这种分离可以防止提议者审查特定的交易或使用MEV(最大可提取价值)获利。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;2. 提议者/建造者分离 (Proposer/Builder Separation， 简称 PBS)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;与RBS类似，PBS也将区块提议和构建职责分离，但没有中继者的角色。&lt;/li&gt;
&lt;li&gt;建造者直接将区块提交给提议者，提议者进行选择和验证。&lt;/li&gt;
&lt;li&gt;PBS旨在通过减少角色和简化流程，进一步去中心化并提高效率。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2024.4.24&lt;/h3&gt;
&lt;h4&gt;V神提出的彩虹质押&lt;/h4&gt;
&lt;p&gt;Vitalik Buterin在ETHTaipei 2024活动上提出了&quot;彩虹质押&quot;(Rainbow Staking)的概念，这是一个允许协议服务提供商(无论是&quot;个人&quot;还是&quot;专业&quot;)最大限度地参与差异化协议服务菜单的概念框架。&lt;/p&gt;
&lt;p&gt;彩虹质押旨在解决以下问题:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;进一步整合&quot;即插即用&quot;方式的协议服务&lt;/li&gt;
&lt;li&gt;防止出现取代以太币成为网络代币的主导性LST(流动性质押代币)&lt;/li&gt;
&lt;li&gt;通过提供参与不同服务类别的机会，增强个人质押者的经济价值和代理权&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;彩虹质押处理&quot;重质押&quot;(heavy staking)和&quot;轻质押&quot;(light staking)两类服务:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;重质押是可削减的，并在每个时隙签名&lt;/li&gt;
&lt;li&gt;轻质押是不可削减的，通过抽签系统被提取签名时隙&lt;/li&gt;
&lt;li&gt;两者都需要签署区块才能最终确定该区块&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但彩虹质押仍需更多的研究和开发，才能成为以太坊长期质押的可行设计。Vitalik指出，最大的问题不是技术性的，而是哲学性的，即如何让&quot;懒惰的以太币持有者&quot;参与保护以太坊网络。&lt;/p&gt;
&lt;h3&gt;2024.4.23&lt;/h3&gt;
&lt;h4&gt;PEPC (Proposer Efficiency and Privacy with Commit) 机制&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;通过学习 https://github.com/eth-protocol-fellows/protocol-studies/blob/pbs/docs/wiki/research/PBS/PEPC.md 内容，了解到以下内容&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;PEPC 旨在提高区块构建者(builders)的效率和隐私性，同时防止审查。它要求区块提议者(proposers)先提交一个承诺(commitment)，然后再披露区块内容。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PEPC 的工作原理是:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;构建者生成一个区块，将其与一个随机数一起哈希，得到一个承诺。&lt;/li&gt;
&lt;li&gt;构建者将承诺发送给提议者。提议者选择一个承诺，将其包含在信标链区块中。&lt;/li&gt;
&lt;li&gt;在下一个时隙，构建者披露区块内容和随机数，证明其与先前的承诺相对应。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PEPC 有几个优点:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在提议者没有披露区块内容的情况下，构建者可以开始构建下一个区块，提高了效率。&lt;/li&gt;
&lt;li&gt;提议者在构建者披露区块内容之前，无法审查特定交易。&lt;/li&gt;
&lt;li&gt;通过使用 VDF (Verifiable Delay Function)，可以抵抗 DoS 攻击。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PEPC 的一些权衡和开放性问题包括:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;构建者在披露区块之前可能会撤回，造成区块丢失。&lt;/li&gt;
&lt;li&gt;恶意构建者可能会提交无效的承诺。需要一些机制来惩罚这种行为。&lt;/li&gt;
&lt;li&gt;实现 VDF 可能具有挑战性。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;2024.4.22&lt;/h3&gt;
&lt;h4&gt;以太坊中的最大可提取价值MEV&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;https://ethereum.org/zh/developers/docs/mev/&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这篇文章主要介绍了以太坊中的最大可提取价值(MEV)概念:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;MEV的定义:
MEV指通过在区块中包含、排除和更改交易顺序而获得的最大价值。这些操作由拥有交易排序权的参与者(如矿工)执行。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MEV的起源:
MEV最初被称为&quot;矿工可提取价值&quot;，因为在工作量证明系统中，矿工控制交易的包含和排序。但在权益证明系统中，验证者和区块构建者也可以提取MEV，因此现在称为&quot;最大可提取价值&quot;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MEV的例子:
常见的MEV机会包括DEX套利、清算、夹心交易等。搜索者编写复杂算法来检测盈利的MEV机会。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MEV的影响:
MEV有积极和消极的影响。积极的是，MEV可以使DeFi协议更加稳定和有用。消极的是，MEV可能导致网络拥塞、用户体验变差、共识不稳定等问题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MEV的状况:
2021年MEV开采量剧增，导致矿工费价格极高。Flashbots的MEV中继的出现，降低了普通抢跑者的效力，并将矿工费价格拍卖带出链外，降低了普通用户的矿工费。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;权益证明下的MEV:
在权益证明系统下，区块生产被分成构建(由区块构建者完成)和提议(由验证者完成)。构建者负责打包交易，可以从MEV中获利。中继者负责将交易包传送给提议者。托管负责存储构建者发送的区块体和验证者发送的区块头。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;2024.4.21&lt;/h3&gt;
&lt;h5&gt;以太坊共识客户端teku&lt;/h5&gt;
&lt;h2&gt;以太坊 Teku 架构详解&lt;/h2&gt;
&lt;p&gt;Teku 是由 ConsenSys 开发的开源以太坊共识客户端，包含完整的信标链节点和验证者客户端实现。它采用 Java 编写，并以 Apache 2.0 许可证发布。&lt;/p&gt;
&lt;h3&gt;Teku 的主要组件&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;信标节点 (Beacon Node):&lt;/strong&gt; 信标节点是 Teku 的核心组件之一。它连接到以太坊 2.0 网络，负责同步和验证区块，并维护最新的网络状态。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;验证者客户端 (Validator Client):&lt;/strong&gt; 验证者客户端负责管理验证者的密钥和签名操作。它与信标节点通信，根据信标链的状态参与证明权益共识过程。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;存储:&lt;/strong&gt; Teku 使用 LevelDB 作为底层存储，用于存储区块、状态和其他链数据。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;网络:&lt;/strong&gt; Teku 使用 libp2p 网络库与其他节点通信，并实现了以太坊 2.0 的网络协议。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;共识:&lt;/strong&gt; Teku 实现了以太坊 2.0 的 Gasper 共识算法，包括 Casper FFG 和 LMD GHOST。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;API:&lt;/strong&gt; Teku 提供了 REST API 和 JSON-RPC API，允许外部应用程序与之交互。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Teku 的同步模式&lt;/h3&gt;
&lt;p&gt;Teku 支持多种同步模式，以适应不同的使用场景和性能要求:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;快照同步 (Snap Sync):&lt;/strong&gt; 这是 Teku 的默认同步模式。它从一个可信的检查点开始同步，并下载最新的状态快照，以快速同步到网络的当前状态。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;完全同步 (Full Sync):&lt;/strong&gt; 在完全同步模式下，Teku 从创世区块开始同步，并逐个验证每个区块，以建立完整的区块链状态。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;归档同步 (Archive Sync):&lt;/strong&gt; 归档同步类似于完全同步，但它会存储所有的历史状态，而不仅仅是最新的状态。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Teku 的可扩展性和安全性&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Teku 在设计时考虑了可扩展性和安全性。它支持单独运行信标节点和验证者客户端，以提高安全性。Teku 还与 Web3Signer 集成，以实现签名密钥的安全存储和防双签保护。是一个功能完备、架构良好的以太坊 2.0 客户端。它提供了灵活的部署选项、多种同步模式以及与以太坊生态系统的无缝集成，是机构级用户和企业的理想选择。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2024.4.20&lt;/h3&gt;
&lt;h4&gt;Study Group Week 7 | Verkle Trees&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;关于verkle树的学习，已经在week3 中有过总结 ，在此只记录下视频中提到的如何将以太坊状态转换为verkle树的过程。
Converting the Ethereum state into a Verkle tree is a complex process with ongoing research. Here&apos;s a breakdown of the key aspects:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Challenges:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Data Size:&lt;/strong&gt; The Ethereum state is massive， and converting it all at once is impractical. The process needs to be batched and optimized for efficiency.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;State Updates:&lt;/strong&gt;  Ethereum is constantly evolving， with new data added and existing data modified through transactions. The conversion needs to account for these ongoing updates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trade-offs:&lt;/strong&gt; While Verkle trees offer efficiency benefits， there might be trade-offs in terms of complexity and gas costs for specific operations compared to the current Merkle Patricia Trie (MPT).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;General Steps (Conceptual):&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Preparation:&lt;/strong&gt; Identify a starting point (block) and determine the size of data batches for conversion.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Iterative Conversion:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Extract a batch of state data from the existing MPT.&lt;/li&gt;
&lt;li&gt;Process the data and organize it according to the Verkle tree structure. This involves hashing and creating Merkle proofs.&lt;/li&gt;
&lt;li&gt;Store the Verkle tree representation of the batch.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;State Updates:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;As new transactions occur， update the corresponding sections in the Verkle tree efficiently. This might involve partial updates or witness creation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Verification:&lt;/strong&gt; Implement mechanisms to verify the integrity of the Verkle tree data.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;2024.4.19&lt;/h3&gt;
&lt;h4&gt;了解以太坊的EL Client Reth&lt;/h4&gt;
&lt;h5&gt;What are the goals of Reth?&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;Modularity&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Every component of Reth is built to be used as a library: well-tested， heavily documented and benchmarked. We envision that developers will import the node&apos;s crates， mix and match， and innovate on top of them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Examples of such usage include， but are not limited to， spinning up standalone P2P networks， talking directly to a node&apos;s database， or &quot;unbundling&quot; the node into the components you need.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To achieve that， we are licensing Reth under the Apache/MIT permissive license.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;Performance&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Reth aims to be fast， so we used Rust and the Erigon staged-sync node architecture.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We also use our Ethereum libraries (including Alloy and revm) which we’ve battle-tested and optimized via Foundry.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;Free for anyone to use any way they want&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Reth is free open source software， built for the community， by the community.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;By licensing the software under the Apache/MIT license， we want developers to use it without being bound by business licenses， or having to think about the implications of GPL-like licenses.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;Client Diversity&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;The Ethereum protocol becomes more antifragile when no node implementation dominates. This ensures that if there&apos;s a software bug， the network does not finalize a bad block. By building a new client， we hope to contribute to Ethereum&apos;s antifragility.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;Used by a wide demographic&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;We want to solve for node operators that care about fast historical queries， but also for hobbyists who cannot operate on large hardware.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We also want to support teams and individuals who want both sync from genesis and via &quot;fast sync&quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We envision that Reth will be configurable enough for the tradeoffs that each team faces.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2024.4.18&lt;/h3&gt;
&lt;h4&gt;数据分片和DAS提案解释&lt;/h4&gt;
&lt;p&gt;今天学习了v神发布的一篇&lt;a href=&quot;https://hackmd.io/@vbuterin/sharding_proposal&quot;&gt;文章&lt;/a&gt;，是一份提案，该提案使用侧重数据可用性的方法来构建以太坊分片实现的第 1 阶段。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;信标链的主要新增内容将是一个 ShardDataHeader 对象的向量，每个分片一个。ShardDataHeader 表示大量的底层数据(大小为 0-512 kB)。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;只有当 ShardDataHeader 所指向的底层数据可用时，区块才有效，这意味着它已经发布到网络上，任何人都可以下载。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;为了保持可扩展性，客户端在验证区块时不会下载每个 ShardDataHeader 的完整底层数据。相反，他们将使用一种称为数据可用性抽样的间接技术来验证数据可用性。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;文章还讨论了与分片实现相关的一些参数，例如分片数量、每个 epoch 的槽位数以及每个委员会周期的槽位数。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;提出了一种侧重数据可用性的方法，用于以太坊分片实现的第 1 阶段，引入了 ShardDataHeader 对象和数据可用性抽样，以确保数据可用性，同时保持可扩展性。&lt;/p&gt;
&lt;h3&gt;2024.4.17&lt;/h3&gt;
&lt;h4&gt;以太坊共识层和执行层规范&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;通过阅读week6中的资料&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;https://github.com/ethereum/consensus-specs&lt;/li&gt;
&lt;li&gt;https://blog.ethereum.org/2023/08/29/eel-spec&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;共识层规范(Consensus Layer Spec):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;以太坊共识层负责维护以太坊区块链的安全性和一致性，目前采用的是权益证明(PoS)共识机制。&lt;/li&gt;
&lt;li&gt;在PoS下，验证者需要质押ETH作为抵押，并参与区块提议和投票过程。验证者的权重与其质押的ETH数量成正比。&lt;/li&gt;
&lt;li&gt;为了防止验证者作恶，以太坊引入了罚没机制。如果验证者违反协议，其质押的部分ETH将被罚没。&lt;/li&gt;
&lt;li&gt;共识层的主要组件包括信标链(Beacon Chain)、分片(Sharding)等。信标链是PoS的核心，负责管理验证者集合和协调分片。&lt;/li&gt;
&lt;li&gt;未来以太坊计划实现Danksharding，进一步提高可扩展性。Danksharding允许验证者只保存和验证分片数据的一部分。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;执行层规范(Execution Layer Spec):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;以太坊执行层负责处理交易和维护状态，目前采用的是以太坊虚拟机(EVM)。&lt;/li&gt;
&lt;li&gt;EVM是一个图灵完备的虚拟机，支持通过智能合约执行任意复杂度的计算。&lt;/li&gt;
&lt;li&gt;执行层的关键组件包括交易池(Txpool)、状态存储(State)、收据存储(Receipt)等。&lt;/li&gt;
&lt;li&gt;为了提高执行层的可读性和可维护性，以太坊社区推出了以太坊执行层规范(EELS)。&lt;/li&gt;
&lt;li&gt;EELS是用Python编写的执行层参考实现，为每个分叉提供了完整的协议快照，有助于开发者理解和实现EIP。&lt;/li&gt;
&lt;li&gt;EELS的目标是成为指定核心EIP的默认方式，也是EIP作者首先用来原型开发提案的工具。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2024.4.16&lt;/h3&gt;
&lt;h4&gt;以太坊节点架构&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;通过阅读  https://ethereum.org/en/developers/docs/nodes-and-clients/node-architecture/ 了解了以太坊节点架构&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;以太坊节点由两个客户端组成:执行客户端和共识客户端。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在以太坊使用工作量证明时，只需要执行客户端就可以运行一个完整的以太坊节点。但自从实施权益证明后，执行客户端需要与另一个称为&quot;共识客户端&quot;的软件一起使用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;两个客户端分别连接到各自的对等网络(P2P)。执行客户端通过P2P网络传播交易，管理本地交易池，而共识客户端通过P2P网络传播区块，实现共识和区块链增长。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;执行客户端的作用包括:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;作为以太坊的用户网关&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;包含以太坊虚拟机、以太坊状态和交易池&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提供JSON-RPC接口供用户查询区块链、提交交易和部署智能合约&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;共识客户端的作用是参与权益证明共识，验证执行客户端的计算结果。节点运营者可以通过在质押合约中存入32 ETH来给共识客户端添加验证者角色。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;新的以太坊节点架构采用模块化设计，由执行客户端和共识客户端组成，分工明确，共同维护以太坊网络的安全和去中心化。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2024.4.15&lt;/h3&gt;
&lt;h4&gt;以太坊存储新解决方案探索&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;自EIP-4844之后，以太坊网络的数据吞吐量与存储压力日益增长，不断增长的存储需求为以太坊节点带来了巨大挑战。为了降低存储压力，部分以太坊客户端对本地存放的以太坊历史数据进行删剪，不同的全节点在存储行为上的一致性被逐渐瓦解。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;EIP-4444：限制执行客户端中的历史数据：该提案允许客户端删除超过一年的过往区块。假设平均区块大小为 100K，历史块数据上限约为 250 GB（100K * (3600 * 24 * 365) / 12，假设区块时间 = 12 秒）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;EIP-4844：分片 BLOB 交易：丢弃超过 18 天的 BLOB数据。与 EIP-4444 相比，这是一种更激进的方法，将历史 BLOB 大小限制在 100 GB 左右（(18 * 3600 * 24) * 128K * 6 / 12，假设区块时间 = 12 秒）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;昨天做了执行客户端端的介绍，其中Geth是保留全部数据，并且不提供api进行删减历史数据，而其他客户端如Nethermind 和 Besu 以配置删除某些以太坊历史数据（例如历史区块）。这会让部分客户端节点的行为与其他客户端不一致。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;删除所有客户端的历史数据会产生什么后果？&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;新节点无法通过“full sync”模式来同步到最新状态， “full sync”是一种将历史数据重放，从创世区块同步到最新区块的数据同步方案。相应地，我们必须采取“snap sync”或“state sync”来直接同步以太坊节点的最新状态。这种方法已在 Geth 中实现，并作为默认的同步运行方式。&lt;/li&gt;
&lt;li&gt;节点删除掉以太坊主网历史数据，也会导致以太坊 L2出现问题，即新加入的Layer2节点，无法通过重放 Layer2全部历史数据的方法，同步至当前的最新状态。此外，由于 L1 节点不维护 L2 状态，L2 的“snap sync”方法无法根据Layer1区块直接派生出最新的 Layer2 状态，这违反了Layer2继承以太坊安全所需的重要假设。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;可参考的解决方案&lt;/h5&gt;
&lt;h6&gt;方案1：以太坊 Portal 网络&lt;/h6&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;以太坊 Portal 网络是一个轻量级、去中心化的网络，用于连接到以太坊协议。它提供eth_call，eth_getBlockByNumber等以太坊 JSON-RPC 接口，它将 JSON-RPC 请求转换为对分布式哈希表（DHT)的 P2P 请求，类似于 IPFS 网络。与允许存储任何数据类型且容易受到垃圾数据影响的 IPFS 不同，Portal P2P 网络专门托管以太坊数据，如历史区块头和交易数据，这是通过 Portal 网络内置的轻客户端验证技术来实现的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Portal 网络的一个重要特性是。其轻量级的运行设计以及与资源受限设备的兼容性。它可以运行在具有几MB存储空间和低内存的节点之上，从而促进去中心化。即使是手机或 Raspberry Pi 设备也有可能加入该网络，为解决以太坊DA问题做出贡献。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h6&gt;方案2：EthStorage 网络&lt;/h6&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;EthStorage 网络是一个去中心化的激励存储网络，专门用于存储 EIP-4844 BLOB，并获得 ESP 项目的资助。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;最小信任：与需要中心化数据桥的现有解决方案不同，EthStorage 依赖于以太坊的共识和无需许可的 EthStorage 存储节点的 1/m 信任模型。存储 BLOB 的过程是这样的：用户签署一个携带 BLOB 的交易，调用存储合约的put(key， blob_idx) 方法。然后存储合约将记录 BLOB 哈希在链上。之后存储提供商将直接从以太坊 DA 网络下载并存储 BLOB，从而绕过数据桥问题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;存储成本与激励相一致：当调用 put() 方法时，交易必须发送存储费（通过 msg.value）并存入合约中。在成功链下存储节点提交并验证存储证明后，这个存储费用将随着时间的推移逐渐分配给存储节点。与现有的向出块者(proposer)支付一次性存储费的以太坊存储费模型相比，随着时间的推移，支付的存储费遵循贴现现金流模型——假设随着时间的推移，存储成本将相对于 ETH价格而降低。EthStorage 引入的这一重大创新使得费用和存储节点的存储贡献保持一致。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;存储证明：存储证明是受到数据可用性抽样的启发，而 EthStorage 中的采样是针对一段时间内的保存的BLOB。为了有效地验证链上采样，EthStorage 充分利用了智能合约和最新的 SNARK 技术发展。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;无许可操作：EthStorage 中的任何存储节点只要存储数据并定期在链上提交存储证明，都可以获得报酬。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2024.4.14&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;了解了共识客户端和执行客户端信息&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Consensus Clients&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Client&lt;/th&gt;
&lt;th&gt;占比&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;th&gt;Support&lt;/th&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Grandine&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;beta&lt;/td&gt;
&lt;td&gt;Linux， Win， macOS&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lighthouse&lt;/td&gt;
&lt;td&gt;33.47%&lt;/td&gt;
&lt;td&gt;stable&lt;/td&gt;
&lt;td&gt;Linux， Win， macOS， ARM&lt;/td&gt;
&lt;td&gt;Rust&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lodestar&lt;/td&gt;
&lt;td&gt;0.92%&lt;/td&gt;
&lt;td&gt;stable&lt;/td&gt;
&lt;td&gt;Linux， Win， macOS&lt;/td&gt;
&lt;td&gt;TypeScript&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nimbus&lt;/td&gt;
&lt;td&gt;9.34%&lt;/td&gt;
&lt;td&gt;stable&lt;/td&gt;
&lt;td&gt;Linux， Win， macOS， ARM&lt;/td&gt;
&lt;td&gt;Nim&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prysm&lt;/td&gt;
&lt;td&gt;37.89%&lt;/td&gt;
&lt;td&gt;stable&lt;/td&gt;
&lt;td&gt;Linux， Win， macOS， ARM&lt;/td&gt;
&lt;td&gt;Golang&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Teku&lt;/td&gt;
&lt;td&gt;18.39%&lt;/td&gt;
&lt;td&gt;stable&lt;/td&gt;
&lt;td&gt;Linux， Win， macOS&lt;/td&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Data provided by Sigma Prime&apos;s Blockprint — updated daily.
Data may not be 100% accurate.&lt;/p&gt;
&lt;h4&gt;Execution Clients&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Client&lt;/th&gt;
&lt;th&gt;占比&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;th&gt;Support&lt;/th&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Akula&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;deprecated&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Besu&lt;/td&gt;
&lt;td&gt;12%&lt;/td&gt;
&lt;td&gt;stable&lt;/td&gt;
&lt;td&gt;Linux， Win， macOS&lt;/td&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Erigon&lt;/td&gt;
&lt;td&gt;2%&lt;/td&gt;
&lt;td&gt;alpha &amp;amp; beta&lt;/td&gt;
&lt;td&gt;Linux， Win， macOS， ARM&lt;/td&gt;
&lt;td&gt;Golang&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EthereumJS&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;alpha&lt;/td&gt;
&lt;td&gt;Linux， Win， macOS&lt;/td&gt;
&lt;td&gt;TypeScript&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Geth&lt;/td&gt;
&lt;td&gt;63%&lt;/td&gt;
&lt;td&gt;stable&lt;/td&gt;
&lt;td&gt;Linux， Win， macOS， ARM&lt;/td&gt;
&lt;td&gt;Golang&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nethermind&lt;/td&gt;
&lt;td&gt;23%&lt;/td&gt;
&lt;td&gt;stable&lt;/td&gt;
&lt;td&gt;Linux， Win， macOS， ARM&lt;/td&gt;
&lt;td&gt;.NET&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nimbus&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;pre-alpha&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Nim&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reth&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;alpha&lt;/td&gt;
&lt;td&gt;Linux， Win， macOS， ARM&lt;/td&gt;
&lt;td&gt;Rust&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Silkworm&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;pre-alpha&lt;/td&gt;
&lt;td&gt;Linux， Win， macOS&lt;/td&gt;
&lt;td&gt;C++&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Data provided by supermajority.info — updated manually.
Data may not be 100% accurate.&lt;/p&gt;
&lt;h5&gt;Client Diversity Is Not Optional&lt;/h5&gt;
&lt;blockquote&gt;
&lt;p&gt;许多人知道客户端的多样性对于构建一个更有韧性的网络非常重要，但他们不明白为什么这么重要，或者它的重要性到底有多大。这不仅仅是重要——它是至关重要的。如果有一个单一的客户端被三分之二（66%）的验证者使用，这将非常真实地带来中断链条和节点操作者经济损失的风险。
达到最终一致性需要三分之二的验证者。如果一个拥有超过66%市场份额的客户端出现了一个错误，并分叉到它自己的链上，它将能够完成最终确定。一旦分叉完成最终确定，验证者就无法返回到真正的链上，而不被惩罚。如果66%的链同时被惩罚，那么罚款就是全部的32 ETH。
那么，为什么超过50%的市场份额仍然危险呢？如果一个少数客户端分叉，那么超过50%的多数客户端可以获得超过66%的多数。如果没有任何一个客户端的市场份额超过33%，这些情况就可以避免。这就是为什么所有客户端的目标市场份额是小于33%。
执行客户端也不是免疫的。上面提到的风险同样适用于共识客户端和执行客户端。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;2024.4.13&lt;/h3&gt;
&lt;h4&gt;zk/op rollup&lt;/h4&gt;
&lt;p&gt;ZK Rollups和Optimistic Rollups是以太坊上两种主要的二层扩容解决方案，它们都通过将交易计算和存储转移到链下，同时依赖以太坊主链的安全性来显著提高交易吞吐量和降低成本。下面详细解释它们的原理和区别:&lt;/p&gt;
&lt;h5&gt;ZK Rollups&lt;/h5&gt;
&lt;p&gt;ZK Rollups利用零知识证明技术，在链下执行交易并生成加密证明，证明这些交易的正确性和合法性，然后将证明提交到主链进行验证。主要特点包括:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通过压缩交易数据和使用通用或专用电路生成证明，显著减少在主链上的数据量&lt;/li&gt;
&lt;li&gt;主链只需验证证明的合法性，不需要重放所有交易，因此验证成本相对较低(每个批次约50万gas)&lt;/li&gt;
&lt;li&gt;提取资金非常快，只需等待下一个批次的交易&lt;/li&gt;
&lt;li&gt;零知识证明技术相对复杂，通用计算电路的证明生成成本很高&lt;/li&gt;
&lt;li&gt;代表项目有zkSync、Loopring、Starkware等&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Optimistic Rollups&lt;/h5&gt;
&lt;p&gt;Optimistic Rollups采用欺诈证明，乐观地假设链下的交易都是正确的，除非有人提出质疑并提供欺诈证明。主要特点包括:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;将批量交易数据作为简单的状态根变更提交到主链，每个批次的固定成本只有4万gas&lt;/li&gt;
&lt;li&gt;如果有错误交易，需要在挑战期内提交欺诈证明，因此提款需要等待1周左右&lt;/li&gt;
&lt;li&gt;技术门槛相对较低，更容易实现EVM兼容的通用计算&lt;/li&gt;
&lt;li&gt;每笔交易在链上的成本相对ZK Rollup略高，因为需要将完整交易数据发布上链&lt;/li&gt;
&lt;li&gt;代表项目有Optimism、Arbitrum等&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;https://www.aicoin.com/article/324592.html&lt;/p&gt;
&lt;h3&gt;2024.4.12&lt;/h3&gt;
&lt;h4&gt;EIP-4844&lt;/h4&gt;
&lt;p&gt;EIP-4844 被称为 proto-danksharding，它是以太坊的 Dencun 硬分叉中包含的一组升级提案之一。&lt;/p&gt;
&lt;h5&gt;EIP-4844 的技术细节&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;引入「blob」数据块 本质上是大数据包，可以比当前以太坊使用的 calldata 更有效地处理和存储数据。这些 blob 可以存储大量信息，例如去中心化交易所的订单簿数据。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;区块链验证的权衡：验证器节点（以前称为矿工）仍然需要完全验证交易本身，但他们可以選擇不下载和验证相关联的 blob 数据。这降低了运行以太坊节点所需的计算量和存储空间。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rollup 是以太坊扩展解决方案的重要组成部分，它们将交易数据存储在链下，以降低成本并提高吞吐量。EIP-4844 将允许 rollup 使用这些 blob 来存储交易数据，而无需将其包含在主网上需要支付 gas 费用的每一笔交易中。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据有效期有限：为了平衡去中心化和可扩展性，EIP-4844 规定了 blob 数据的有效期。这些数据块仅在共识层上存储有限的时间（通常约 18 天），然后将被删除。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;EIP-4844 如何降低 &lt;code&gt;gas&lt;/code&gt; 费用？&lt;/h5&gt;
&lt;p&gt;它提出了一种新的交易类型，称为「blob携带交易 (&lt;code&gt;blob-carrying transactions&lt;/code&gt;)」。这种交易类似于附加在以太坊交易上的「sidecar」，可以包含额外的信息块。这些 blob 的体积很大（最大可达 128 KB），但与当前的 calldata 相比费用更低。通过将这些 blob 临时存储在以太坊的共识层上，EIP-4844 旨在显着降低 rollup 向以太坊主网传输数据的成本，从而实现降低交易费用。&lt;/p&gt;
&lt;h5&gt;EIP-4844 的优点&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;降低交易费用：EIP-4844 的主要优势之一是降低交易费用。通过将交易数据和执行分开，EIP-4844 使得 rollup 等第 2 层扩展解决方案可以更便宜地存储数据。&lt;/li&gt;
&lt;li&gt;为分片扩展奠定基础：EIP-4844 的设计与以太坊未来的分片扩展路线图兼容。分片是一种将区块链数据分布到多个分片中的方法，可以显着提高可扩展性。EIP-4844 引入了分片所需的一些技术要素，例如 blob 和分离的交易数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;EIP-4844 的潜在影响&lt;/h5&gt;
&lt;p&gt;EIP-4844 预计将对以太坊生态系统产生重大影响。它可以降低交易费用，使以太坊对更广泛的用户和用例更具吸引力。它还可以通过为分片扩展奠定基础，为以太坊的可扩展性带来长期收益。&lt;/p&gt;
&lt;p&gt;EIP-4844 的重要之处在于它可以在不增加去中心化性的情况下提高可扩展性。虽然共识节点需要下载这些 blob，但由于它们仅保存有限的时间，因此不会对长期存储需求造成太大压力。&lt;/p&gt;
&lt;p&gt;EIP-4844 将为以太坊带来以下好处：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;降低 Layer 2 rollup 解决方案的交易费用&lt;/li&gt;
&lt;li&gt;为以太坊未来更复杂的扩容方案（例如完整分片）奠定基础&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2024.4.11&lt;/h3&gt;
&lt;h4&gt;ethereum/execution-spec-tests&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;ethereum/execution-spec-tests&lt;/code&gt;框架收集并执行测试用例，以生成测试夹具（JSON），任何执行客户端都可以使用该夹具来验证其以太坊/执行规范的实现。fixture定义了状态转换和块测试，由框架使用大多数执行客户端提供的 &lt;code&gt;t8n&lt;/code&gt; 命令行工具之一来生成.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Client&lt;/th&gt;
&lt;th&gt;t8n Tool&lt;/th&gt;
&lt;th&gt;Tracing Support&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ethereum/evmone&lt;/td&gt;
&lt;td&gt;evmone-t8n&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ethereum/execution-specs&lt;/td&gt;
&lt;td&gt;ethereum-spec-evm&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ethereum/go-ethereum&lt;/td&gt;
&lt;td&gt;evm t8n&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;hyperledger/besu&lt;/td&gt;
&lt;td&gt;evm t8n-server&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;status-im/nimbus-eth1&lt;/td&gt;
&lt;td&gt;t8n&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h5&gt;配置测试环境&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;sudo add-apt-repository -y ppa:ethereum/ethereum
sudo apt-get update
sudo apt-get install ethereum solc
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;git clone https://github.com/ethereum/execution-spec-tests
cd execution-spec-tests
python3 -m venv ./venv/
source ./venv/bin/activate
pip install -e &apos;.[docs，lint，test]&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;验证测试环境&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;fill --collect-only
fill -v tests/berlin/eip2930_access_list/test_acl.py
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;增加新测试用例&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;📁 execution-test-specs/
├─╴📁 tests/
|   ├── 📄 __init__.py
│   ├── 📁 cancun/
|   |    ├── 📄 __init__.py
│   |    └── 📁 eip4844_blobs/
|   |        ├── 📄 __init__.py
|   |        ├── 📄 test_blobhash_opcode.py
|   |        ├── 📄 test_excess_blob_gas.py
|   |        └── 📄 ...
|   ├── 📁 shanghai
|   |    ├── 📁 eip3651_warm_coinbase
|   |    |   ├── 📄 __init__.py
|   |    |   └── 📄 test_warm_coinbase.py
|   |    ├── 📁 eip3855_push0
|   |    |   ├── 📄 __init__.py
|   |    |   └── 📄 test_push0.py
|   |    ├── 📁...
|   |    ...
│   └── 📁 ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每个测试用例都被定义为一个Python函数，该函数通过使用框架提供的 state_test 或 blockchain_test 对象之一来定义单个 StateTest 或 BlockchainTest 。测试用例和测试模块必须满足以下要求：&lt;/p&gt;
&lt;h2&gt;Ethereum Test Case Requirements&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Requirement&lt;/th&gt;
&lt;th&gt;When&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Be decorated with validity markers&lt;/td&gt;
&lt;td&gt;If the test case is not valid for all forks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Use one of &lt;code&gt;state_test&lt;/code&gt; or &lt;code&gt;blockchain_test&lt;/code&gt; in its function arguments&lt;/td&gt;
&lt;td&gt;Always&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Call the &lt;code&gt;state_test&lt;/code&gt; or &lt;code&gt;blockchain_test&lt;/code&gt; in its test body&lt;/td&gt;
&lt;td&gt;Always&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add a reference version of the EIP spec under test&lt;/td&gt;
&lt;td&gt;Test path contains &lt;code&gt;eip&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;对于状态测试：
&lt;code&gt;def test_access_list(state_test: StateTestFiller):&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;对于区块链测试：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def test_contract_creating_tx(
    blockchain_test: BlockchainTestFiller， fork: Fork， initcode: Initcode
):
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;state_test&lt;/code&gt; 和 &lt;code&gt;blockchain_test&lt;/code&gt; 对象实际上分别是 &lt;code&gt;StateTest&lt;/code&gt; 和 &lt;code&gt;BlockchainTest&lt;/code&gt; 对象的包装器类，它们一旦被调用就实际上实例化这些对象的新实例，并根据测试中定义的前状态和后状态以及事务使用 evm 工具填充测试用例。&lt;/p&gt;
&lt;h3&gt;2024.4.10&lt;/h3&gt;
&lt;h4&gt;ethereum测试&lt;/h4&gt;
&lt;p&gt;Retesteth是以太坊测试工具，用于对以太坊客户端进行共识测试、区块测试、状态测试等。工作流程如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;准备测试用例。Retesteth会读取定义好的测试用例文件，这些文件描述了具体的测试场景，包括预置状态、执行的交易、预期结果等。测试用例存放在tests仓库中。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;配置被测客户端。在运行测试前，需要先设置好待测试的以太坊客户端，如geth、besu、nimbus等。可以通过环境变量、命令行参数等方式传递客户端信息给Retesteth。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;执行测试。通过Retesteth命令行启动测试，它会逐个读取测试用例文件，然后调用以太坊客户端执行相应的测试场景。在测试过程中，Retesteth会:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;将测试用例的预置状态导入到客户端&lt;/li&gt;
&lt;li&gt;发送测试交易给客户端执行&lt;/li&gt;
&lt;li&gt;获取客户端执行完交易后的状态&lt;/li&gt;
&lt;li&gt;将实际状态与预期结果进行比对，判断测试是否通过&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;生成测试报告。测试完成后，Retesteth会生成测试报告，展示测试通过和失败的情况。对于未通过的测试用例，可以分析具体失败的原因，并反馈给客户端开发者进行修复。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;补充测试用例。如果在测试中发现了客户端实现的问题，可以据此补充新的测试用例到tests仓库中，丰富测试内容。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Retesteth作为以太坊规范的参考测试工具，通过运行各类测试场景，验证不同以太坊客户端的一致性，是保障以太坊生态健康发展的重要手段。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Guillaume Ballet的讲座和演示集中讨论了Verkle树带来的技术变化，它们的实现现状，以及无状态以太坊的愿景。开发工作涉及大量关于密码学、数据结构和共识机制的工作，以将Verkle树整合到以太坊中。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;Verkle树简介&lt;/h4&gt;
&lt;p&gt;Verkle树是一种数据结构，代表了从当前以太坊使用的Merkle Patricia树（MPT）的演进。它们结合了向量承诺，允许更高效的数据存储和检索。这种效率对于以太坊的可扩展性和性能改进至关重要。&lt;/p&gt;
&lt;h5&gt;Verkle树的好处&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;更小的证明大小&lt;/strong&gt;：Verkle树显著减少了验证区块链状态所需的证明（见证）的大小。证明大小的减少意味着证明可以更高效地在网络上传递，使新类型的功能成为可能，并使无状态客户端可行。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;更低的硬件要求&lt;/strong&gt;：通过使以太坊状态更加紧凑和证明更小，Verkle树降低了运行以太坊节点的硬件要求。这种改进使得更多设备，甚至可能是智能手机，能够参与网络，从而增强了去中心化。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;新节点更快的同步&lt;/strong&gt;：Verkle树的效率允许新节点加入网络并更快地同步，比当前的MPT更快。这种更快的同步提高了以太坊网络的整体鲁棒性和可访问性。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;可能的更高gas limits&lt;/strong&gt;：减少的计算开销和提高的效率可能允许更高的gas limits，使以太坊能够每秒处理更多交易，提高其可扩展性。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;与未来创新的兼容性&lt;/strong&gt;：Verkle树与未来以太坊创新，如zk-EVMs（零知识以太坊虚拟机）更加兼容。这种兼容性对于以太坊的长期发展及其能够整合尖端加密技术至关重要。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;2024.4.9&lt;/h3&gt;
&lt;h4&gt;关于POS的讨论&lt;/h4&gt;
&lt;p&gt;地址：https://domothy.com/proof-of-stake/&lt;/p&gt;
&lt;p&gt;这篇文章主要讨论了以太坊从工作量证明(PoW)转向权益证明(PoS)共识机制的话题，包括:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;PoS并非一开始就被以太坊采用，主要原因是早期PoS还处于理论研究阶段，存在一些基本问题有待克服，且不同区块链的PoS实现各有利弊，没有放之四海而皆准的方案。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;有观点认为PoS会导致中心化，本质上与PoW类似，拥有更多资金的人可以获得更高的收益。但在PoS下，不管质押10美元还是1000万美元，每个人的收益率是一样的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;虽然没有像PoW那样重复计算哈希，但验证者在PoS下仍然要做&quot;工作&quot;，即创建和验证区块，只是这种工作完全由区块链达成共识所需的有用工作组成。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;文章认为，无论是PoW还是PoS，拥有资金优势的人都能获得更多的算力或质押币，从而获利更多。PoW因规模效应会导致矿池中心化，而PoS下大户的收益率与小户一致。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这篇文章分析了PoS相对PoW的优缺点，指出二者在趋于中心化方面并无本质区别。PoS的核心在于让验证者做有助于区块链共识的有意义工作，而非单纯计算哈希。以太坊选择PoS是经过长期研究和权衡的结果。&lt;/p&gt;
&lt;h3&gt;权益证明（PoS）介绍&lt;/h3&gt;
&lt;p&gt;https://consensys.io/blog/what-is-proof-of-stake&lt;/p&gt;
&lt;p&gt;权益证明（Proof of Stake， PoS）是一种加密货币共识机制，用于验证和添加新的交易记录到区块链。与工作量证明（Proof of Work， PoW）相比，PoS不依赖于矿工通过解决复杂计算问题来竞争新区块的创建权，而是基于参与者持有的加密货币数量和持有时间来选择验证者。&lt;/p&gt;
&lt;h3&gt;PoS的优势&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;能源效率&lt;/strong&gt;：PoS机制不需要大量的计算资源，因此相比PoW，它大大减少了能源消耗。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;降低参与门槛&lt;/strong&gt;：由于不需要昂贵的计算硬件，更多的用户可以参与到验证和维护网络的过程中。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;加强网络安全&lt;/strong&gt;：在PoS中，验证者需要质押（锁定）一定数量的加密货币作为参与验证的“抵押”。如果验证者试图攻击网络或验证不正确的交易，他们将有可能失去部分或全部的质押资金。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;更公平的奖励分配&lt;/strong&gt;：所有验证者根据他们质押的资金比例获得奖励，这意味着收益率对于大户和小户是一致的。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;以太坊2.0和PoS&lt;/h3&gt;
&lt;p&gt;以太坊2.0是以太坊网络的一次重大升级，其核心是从PoW转向PoS共识机制。这一转变旨在解决以太坊当前面临的扩展性、能源效率和安全性问题。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;更高的交易吞吐量&lt;/strong&gt;：通过引入分片技术和PoS，以太坊2.0旨在大幅提高网络的处理能力，使其能够处理更多的交易和应用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;更低的参与门槛&lt;/strong&gt;：与PoW相比，PoS允许更多的用户以较低的成本参与到网络的维护中，增加了网络的去中心化程度和安全性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;环境友好&lt;/strong&gt;：PoS显著减少了能源消耗，与日益增长的环保意识相符。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;权益证明机制为加密货币网络提供了一种更加高效、安全和环保的共识机制。以太坊2.0的升级标志着对这一机制的重大采纳，预计将为整个区块链行业带来深远的影响。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Proof of Stake addresses the three issues of PoW chains discussed earlier - accessibility， centralization， and especially scalability:&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;如何在POS中处理网络中的故障或恶意节点&lt;/h4&gt;
&lt;p&gt;在权益证明(PoS)共识机制中，分布式网络通过拜占庭容错(BFT)算法来处理故障或恶意节点的问题，以确保网络的正常运行。具体来说:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;PoS网络利用BFT算法在存在一定数量的故障或恶意节点的情况下仍能达成共识，只要故障节点的数量不超过一定阈值。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;验证者需要质押(锁定)一定数量的加密货币作为抵押。如果验证者试图攻击网络或验证错误的交易，他们将损失部分或全部的质押资金作为惩罚。这种惩罚机制激励验证者诚实行事。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一些PoS区块链会对验证者的停机时间进行严厉惩罚，如果他们的在线时间低于一定阈值，就会销毁(&quot;削减&quot;)部分质押的币。这促使验证者保持高水平的可用性。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PoS共识的安全性直接掌握在那些维护网络并在协议中持有原生加密资产的人手中。与PoW相比，这种架构能更好地将网络安全与参与者的经济利益绑定在一起。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;尽管PoS在安全性方面可能不如PoW得到充分验证，但通过质押、惩罚和激励等机制，PoS网络能有效应对故障和恶意行为，维护系统的可靠运行。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;PoS网络主要通过BFT算法、质押和惩罚机制来处理故障或恶意节点。通过将验证者的经济利益与诚实行为绑定，并对不当行为进行严厉惩罚，PoS激励验证者维护网络的安全和可用性，从而确保系统在存在一定比例的拜占庭节点时仍能正常运行。&lt;/p&gt;
&lt;h3&gt;2024.4.8&lt;/h3&gt;
&lt;h4&gt;信标链(Beacon Chain)&lt;/h4&gt;
&lt;p&gt;信标链是以太坊2.0 PoS共识系统的核心协调机制。学习总结下它的工作原理:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;信标链是一个独立的区块链，与以太坊主链并行运行。它负责管理PoS协议并协调验证者网络。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;验证者持有32个ETH来参与共识过程。它们被信标链随机分配到每个槽位(12秒)至少128个验证者的“委员会”中，以提出和验证新区块。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;信标链将时间组织为“插槽”(12秒)和“epoch”(32个插槽，约6.4分钟)。每个槽位都有一个由信标链选择的区块提议者来创建一个新的区块。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;每个槽位委员会中的验证者通过广播“证明”对提议的区块进行投票。当委员会的绝对多数成员证明了一个区块时，它就会被添加到信标链。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在每个epoch的开始，信标链从前一个epoch指定一个检查点块。如果代表总以太坊2/3的验证者投票支持该检查点，它就变得“合理”。如果下一个epoch的检查点也被证明是合理的，那么前一个检查点就会“最终确定”，这意味着它是不可逆的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;信标链根据验证者的表现对其进行奖励和惩罚，并通过“砍”来惩罚恶意行为，导致验证者失去一些押注的ETH。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;https://consensys.io/blog/the-ethereum-2-0-beacon-chain-is-here-now-what&lt;/p&gt;
&lt;h3&gt;2024.4.7&lt;/h3&gt;
&lt;h4&gt;节点和客户端&lt;/h4&gt;
&lt;p&gt;在以太坊网络中，节点可以是轻节点、全节点或存档节点。轻节点只下载区块头，而不是整个区块链的所有数据，这使得它们可以快速同步并验证数据的有效性。全节点则存储整个区块链的数据，并参与到区块的验证过程中。存档节点存储了全节点的所有信息，并且还建立了历史状态的存档。&lt;/p&gt;
&lt;p&gt;以太坊客户端的功能包括创建和管理钱包、发送交易、查询区块链信息、与智能合约交互以及管理本地节点等。&lt;/p&gt;
&lt;p&gt;以太坊节点和客户端的设计旨在支持去中心化，确保网络的安全性和可靠性。每个节点都运行着以太坊虚拟机（EVM）并执行相同的指令，这些节点彼此平等，实时沟通同步区块资料，以维持以太坊区块链的运作。&lt;/p&gt;
&lt;p&gt;https://ethereum.org/en/developers/docs/nodes-and-clients/&lt;/p&gt;
&lt;p&gt;https://cs251.stanford.edu/lectures/lecture7.pdf&lt;/p&gt;
&lt;h4&gt;Execution Layer node&lt;/h4&gt;
&lt;p&gt;以太坊执行层节点是以太坊网络中的一种节点，负责执行交易和智能合约的代码。执行层节点运行着以太坊虚拟机（EVM），这是一个全局的、沙盒化的执行环境，可以精确地执行智能合约的字节码。EVM确保了智能合约在不同节点上的执行结果是一致的，从而维护了网络的同步和共识。&lt;/p&gt;
&lt;p&gt;执行层节点通过验证和执行交易，来维护以太坊区块链的状态。每个执行层节点都会验证每个区块中的所有交易，并执行这些交易中定义的智能合约代码。这个过程包括计算交易费用、更新账户余额、执行智能合约的函数调用等。执行层节点还负责创建新的区块，并将这些区块广播到网络中的其他节点。&lt;/p&gt;
&lt;p&gt;执行层节点与共识层节点（Consensus Layer node）一起工作，共识层节点负责网络的共识机制，例如在以太坊2.0中的权益证明（Proof of Stake， PoS）机制。执行层节点提供了执行交易和合约的功能，而共识层节点则确保了区块的产生和链的安全性。&lt;/p&gt;
&lt;p&gt;以太坊客户端软件，如Geth或Parity，通常包含了执行层的功能。这些客户端软件实现了以太坊的规范，并通过点对点网络与其他以太坊客户端通信。不同的客户端软件可能用不同的编程语言编写，但它们都遵循相同的协议规则，因此可以互操作。&lt;/p&gt;
&lt;p&gt;https://ethereum.stackexchange.com/questions/136728/who-runs-the-evm&lt;/p&gt;
&lt;h4&gt;State transition function&lt;/h4&gt;
&lt;p&gt;以太坊的状态转换函数是以太坊区块链核心概念之一，它描述了如何从当前的全局状态转换到下一个状态。这个过程是以太坊执行交易和智能合约的基础。&lt;/p&gt;
&lt;p&gt;在以太坊中，全局状态是由所有账户的当前状态（包括它们的余额、存储的数据和代码）组成的。每当一个交易被执行时，状态转换函数就会被调用来更新全局状态。这个函数接受当前的全局状态和一个交易作为输入，输出一个新的全局状态。&lt;/p&gt;
&lt;p&gt;状态转换函数的工作流程大致如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;验证交易&lt;/strong&gt;：首先验证交易的有效性，包括签名的验证和交易发起者账户余额是否足够支付交易费用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;执行交易&lt;/strong&gt;：然后根据交易的内容执行相应的操作。这可能包括转移以太币、执行智能合约代码或创建新的智能合约。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;更新状态&lt;/strong&gt;：执行交易后，更新全局状态以反映交易的结果。这可能包括改变账户的余额、更新存储的数据或更改智能合约的代码。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;收取交易费&lt;/strong&gt;：最后从交易发起者的账户中扣除交易费用，并将其作为奖励发给矿工或验证者。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;以太坊的状态转换函数是确定性的，如果给定相同的输入（当前状态和交易），它总是产生相同的输出（新状态）。这保证了所有节点在处理相同的交易集合时，最终会达成相同的全局状态，从而维护了区块链的一致性和安全性。&lt;/p&gt;
&lt;h3&gt;2024.4.6&lt;/h3&gt;
&lt;h4&gt;p2p网络&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;P2P网络，又叫点对点网络，是一种去中心化的网络结构，其中每个网络节点既是客户端又是服务器，能够直接与其他节点进行通信和数据交换。这种网络结构允许节点共享资源，如文件、存储空间或带宽，无需依赖中央服务器&lt;/li&gt;
&lt;li&gt;P2P网络的工作原理是基于对等的节点之间直接进行通信和数据交换，而不依赖于中央服务器。在P2P网络中，每个节点既是客户端也是服务器，可以提供和请求服务。这种网络模型允许节点共享文件、处理器运算能力、存储空间等资源。&lt;/li&gt;
&lt;li&gt;在P2P网络中，节点需要解决如何加入和离开网络、如何在网络中查找和连接到其他节点、以及如何处理节点故障和恢复等问题。为了实现这些功能，P2P网络通常采用特定的通信协议，如Gossip协议，该协议通过节点之间的相互传递信息来实现数据的分发和更新&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;IPFS&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;IPFS（InterPlanetary File System）是一个点对点的分布式文件存储系统，旨在连接所有计算设备具有相同的文件系统。在区块链领域，IPFS常被用来存储不适合直接存储在区块链上的大型数据，例如图片、视频等媒体文件。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;IPFS的工作原理是将文件分割成小块，每一块都通过加密哈希函数生成一个唯一的哈希值。这些哈希值作为文件内容的唯一标识符，可以用来检索文件。当用户需要获取某个文件时，IPFS网络可以利用这些哈希值找到存储相应文件块的节点，并从多个节点处并行下载，提高了数据的检索效率和系统的健壮性。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;IPFS使用分布式哈希表（DHT）来跟踪数据块的位置。DHT是一种用于去中心化网络的键值存储系统，它允许网络中的节点高效地找到存储特定数据的其他节点。IPFS中的DHT基于Kademlia算法，这是一种专为P2P网络设计的DHT。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在区块链中，IPFS可以与智能合约结合使用，以实现去中心化的数据存储解决方案。例如，可以将数据存储在IPFS中，而将数据的哈希值和其他相关信息（如交易地址和签名）存储在区块链上。这样，区块链就可以提供一个不可篡改的数据历史记录，而IPFS则负责存储实际的数据内容。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;IPFS的优势在于它能够解决区块链在数据存储方面的限制，如存储空间和响应时间。通过将数据存储在IPFS上，区块链可以保持轻量级，同时确保数据的不可篡改性和持久性。此外，IPFS的去中心化特性也有助于提高数据存储的安全性和隐私保护。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;今天了解了p2p网络的工作原理和IPFS的优势，以及它们在区块链领域的应用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;https://icommunity.io/en/what-is-ifps-the-hard-drive-for-blockchain/&lt;/p&gt;
&lt;p&gt;https://www.youtube.com/watch?v=vTIfRgoaCIM&lt;/p&gt;
&lt;h4&gt;Ethereum in 30 minutes video&lt;/h4&gt;
&lt;p&gt;本视频是以太坊联合创始人Vitalik Buterin在2022年波哥大Devcon会议上的演讲。在演讲中，Vitalik讨论了以太坊的现状及其未来的发展。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;以太坊是一个去中心化的开源区块链平台，可以创建智能合约和去中心化应用程序(dApps)。智能合约是自动执行的合约，其协议条款直接写入代码，允许数字交易自动化和消除中介。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Vitalik讨论了以太坊面临的可扩展性挑战以及为解决这些挑战而开发的解决方案，例如分片和第二层扩展解决方案。分片是一种将以太坊网络分割成更小，更易于管理的碎片的方法，称为分片，这允许更大的可扩展性和更快的交易处理。第2层扩展解决方案，如乐观rollup和zk - rollup，建立在以太坊区块链之上，通过链下处理，然后提交给以太坊网络进行最终结算，从而实现更快、更便宜的交易。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Vitalik还讨论了以太坊从工作量证明(PoW)共识机制向权益证明(PoS)共识机制的过渡，称为以太坊2.0或Serenity。PoS是一种更节能、更环保的共识机制，它用验证者取代了对矿工的需求，验证者将他们的以太币(ETH)用于验证交易并保护网络。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;POW AND POS&lt;/h4&gt;
&lt;p&gt;以太坊的工作量证明（Proof of Work，简称PoW）和权益证明（Proof of Stake，简称PoS）是两种不同的共识机制，用于在去中心化网络中验证交易和创建新区块。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;工作量证明（PoW）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在PoW系统中，矿工使用GPU和ASIC（专用集成电路）等硬件来解决复杂的数学问题，以此来验证交易并创建新的区块。这个过程被称为挖矿。挖矿的矿工会获得新创建的加密货币和交易费用作为奖励。PoW机制提供了很强的网络安全性，但它非常耗能，因为它需要大量的计算能力。这种能源消耗一直是环境倡导者的批评点，并且对网络的可扩展性也有限制。例如，比特币挖矿大约消耗全球0.5%的能源，但每秒只能处理7笔交易。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;权益证明（PoS）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;为了解决PoW带来的能源消耗和可扩展性问题，以太坊在2022年9月完成了从PoW向PoS的重大转变。PoS机制远不像PoW那样耗能，据估计能够将能源消耗减少高达99%。在PoS系统中，不是通过解决数学问题来竞争创建新区块，而是通过持有并愿意“抵押”一定数量的币的验证者来创建新区块。在以太坊中，验证者抵押的是以太币（ETH）。验证者还参与确认提议区块的有效性。这个过程确保了添加到链上的区块是有效的，并且得到了大多数验证者的同意。验证者通过提议新区块和确认交易的有效性来获得奖励，这些奖励来自交易费用，有时还包括新铸造的加密货币。为了确保验证者诚实行事，PoS系统设有一种惩罚措施，称为“削减”。如果验证者试图批准欺诈交易或行为不端，他们抵押的加密货币的一部分或全部可能会被没收或“削减”。这种机制阻止了不诚实的行为。&lt;/p&gt;
&lt;h3&gt;2024.4.5&lt;/h3&gt;
&lt;h4&gt;week0中的Cryptography&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;散列 (Hashing)详解
散列函数像是信息摘要工具，可以将任意长度的输入数据转换成固定长度的输出结果，称为散列值 (Hash 值)。这个过程就像把一堆文件的内容浓缩成一个简短的指纹一样。散列函数有以下关键特性：&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;易于计算 (Easy to Compute)： 任何人都能快速计算出给定数据的散列值。&lt;/li&gt;
&lt;li&gt;抗碰撞 (Collision Resistant)： 对于不同的输入数据，产生相同散列值的可能性极低。就好比不同的人几乎不可能有相同的指纹一样。&lt;/li&gt;
&lt;li&gt;单向性 (One-Way)： 仅凭散列值本身，几乎无法推导出原始的输入数据。就如同指纹只能用来验证身份，却无法还原成完整的个人信息。&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;散列函数在密码学领域有着广泛的应用：&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数字签名 (Digital Signature)： 利用散列函数对数据进行签名，可以确保数据的完整性 and 可靠性 (可靠性 - refers to authenticity in this context)。就好比给重要文件盖上印章，可以验证发送者身份并且确保内容没有被篡改。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据校验 (Data Integrity Check)： 通过比较原始数据的散列值和传输过程中的散列值，可以判断数据是否在传输过程中被修改。就如同核对货物出库时的封条一样，可以确保货物在运输途中没有被掉包。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;密码存储 (Password Storage)： 网站不会存储用户的原始密码，而是存储密码的散列值。这样即使黑客窃取了数据库，也无法获得用户的明文密码。就好比指纹识别系统只存储指纹的特徵，而不是整只手的外貌。
常用的散列函数包括 MD5、SHA-1 和 SHA-2 家族。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;公钥密码学 (Public Key Cryptography)详解
公钥密码学采用密钥对 (Key Pair) 的方式进行加密和解密。密钥对包含公钥 (Public Key) 和私钥 (Private Key)。形象地比喻，公钥就像是邮箱的地址，所有人都可以知道；而私钥就像邮箱的钥匙，只有持有者才能打开邮箱。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;公钥密码学的工作流程如下：&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;加密 (Encryption)： 信息发送者使用接收方的公钥对信息进行加密。 任何人都可以用公钥加密信息，但是只有持有私钥的人才能解密。
解密 (Decryption)： 信息接收者使用自己的私钥解密密文，还原成原始信息。 因为只有持有私钥的人才能解密，所以可以确保信息的保密性。&lt;/p&gt;
&lt;p&gt;常用的公钥密码算法包括 RSA 算法&lt;/p&gt;
&lt;h4&gt;Merkle 树详解&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Merkle 树是一种树形数据结构，常用于高效验证大型数据的完整性。它利用密码学中的散列函数来构建，具有以下特点：&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;数据完整性校验 (Data Integrity Verification)： 可以方便地校验数据块 (Data Block) 的完整性，而无需检查整个数据。&lt;/li&gt;
&lt;li&gt;去重存储 (Deduplication)： 可以识别并消除数据中的重复部分，节省存储空间。&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;Merkle 树的结构&lt;/h5&gt;
&lt;p&gt;Merkle 树由节点 (Node) 组成，每个节点包含以下信息：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据块哈希 (Hash of Data Block)： 对数据块计算所得的散列值。&lt;/li&gt;
&lt;li&gt;子节点哈希 (Hashes of Children Nodes)（可选）： 对于非叶子节点，包含其子节点的哈希值。
Merkle 树的层级结构清晰，叶子节点代表原始数据块的哈希值，非叶子节点的哈希值由其子节点的哈希值计算得到。计算方法通常采用一种称为 &quot;Merkle-Damgård Hash Function&quot; 的技术，例如 SHA-256。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Merkle 树的工作原理&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;在Merkle树中，每个叶子节点都标记了一个数据块的加密哈希值，而每个非叶子节点则标记了其子节点标签的加密哈希值。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;叶子节点的数据先被哈希，然后成对分组。每对节点的哈希值再被哈希，生成它们的父节点。重复这个过程，直到只剩下一个根节点，称为Merkle根。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Merkle树通常使用二叉树结构，即每个节点最多有2个子节点。但也可以使用多叉树，每个节点有多个子节点。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;为了验证某个叶子节点是否属于Merkle树，只需计算沿着该叶子到根的路径上的哈希值，数量与树的深度成正比。这比在哈希列表中逐个检查每个节点要高效得多。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果Merkle树的任何部分发生变化，都会传播到根节点。通过比较根哈希，可以快速检测出数据是否被篡改。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Merkle树的搜索、插入、删除操作复杂度为O(logn)，空间复杂度为O(n)，其中n是叶子节点数。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Merkle树利用哈希指针构建一个树形结构，可以高效地验证大型数据结构的完整性，广泛用于区块链、分布式系统、版本控制等领域中。它通过递归哈希的方式，在保证安全性的同时提供了更好的性能。&lt;/p&gt;
&lt;p&gt;https://www.youtube.com/watch?v=3AcQyTs_Es4&amp;amp;t=0&lt;/p&gt;
&lt;p&gt;https://brilliant.org/wiki/merkle-tree/&lt;/p&gt;
&lt;p&gt;https://www.geeksforgeeks.org/blockchain-merkle-trees/&lt;/p&gt;
&lt;p&gt;https://en.wikipedia.org/wiki/Merkle_tree&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Fuwari-markdown语法扩展</title><link>https://blog.ithuo.net/posts/fuwari-md-syntactic-extend/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/fuwari-md-syntactic-extend/</guid><pubDate>Fri, 10 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;fuwari作者对markdown文件增加了特殊语法解析支持，以下是一些基础示例：&lt;/p&gt;
&lt;h1&gt;An h1 header&lt;/h1&gt;
&lt;p&gt;Paragraphs are separated by a blank line.&lt;/p&gt;
&lt;p&gt;2nd paragraph. &lt;em&gt;Italic&lt;/em&gt;, &lt;strong&gt;bold&lt;/strong&gt;, and &lt;code&gt;monospace&lt;/code&gt;. Itemized lists
look like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;this one&lt;/li&gt;
&lt;li&gt;that one&lt;/li&gt;
&lt;li&gt;the other one&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that --- not considering the asterisk --- the actual text
content starts at 4-columns in.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Block quotes are
written like so.&lt;/p&gt;
&lt;p&gt;They can span multiple paragraphs,
if you like.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Use 3 dashes for an em-dash. Use 2 dashes for ranges (ex., &quot;it&apos;s all
in chapters 12--14&quot;). Three dots ... will be converted to an ellipsis.
Unicode is supported. ☺&lt;/p&gt;
&lt;h2&gt;An h2 header&lt;/h2&gt;
&lt;p&gt;Here&apos;s a numbered list:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;first item&lt;/li&gt;
&lt;li&gt;second item&lt;/li&gt;
&lt;li&gt;third item&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Note again how the actual text starts at 4 columns in (4 characters
from the left side). Here&apos;s a code sample:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Let me re-iterate ...
for i in 1 .. 10 { do-something(i) }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you probably guessed, indented 4 spaces. By the way, instead of
indenting the block, you can use delimited blocks, if you like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;define foobar() {
    print &quot;Welcome to flavor country!&quot;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(which makes copying &amp;amp; pasting easier). You can optionally mark the
delimited block for Pandoc to syntax highlight it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import time
# Quick, count to ten!
for i in range(10):
    # (but not *too* quick)
    time.sleep(0.5)
    print i
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;An h3 header&lt;/h3&gt;
&lt;p&gt;Now a nested list:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;First, get these ingredients:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;carrots&lt;/li&gt;
&lt;li&gt;celery&lt;/li&gt;
&lt;li&gt;lentils&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Boil some water.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dump everything in the pot and follow
this algorithm:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; find wooden spoon
 uncover pot
 stir
 cover pot
 balance wooden spoon precariously on pot handle
 wait 10 minutes
 goto first step (or shut off burner when done)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Do not bump wooden spoon or it will fall.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Notice again how text always lines up on 4-space indents (including
that last line which continues item 3 above).&lt;/p&gt;
&lt;p&gt;Here&apos;s a link to &lt;a href=&quot;http://foo.bar&quot;&gt;a website&lt;/a&gt;, to a &lt;a href=&quot;local-doc.html&quot;&gt;local
doc&lt;/a&gt;, and to a &lt;a href=&quot;#an-h2-header&quot;&gt;section heading in the current
doc&lt;/a&gt;. Here&apos;s a footnote [^1].&lt;/p&gt;
&lt;p&gt;[^1]: Footnote text goes here.&lt;/p&gt;
&lt;p&gt;Tables can look like this:&lt;/p&gt;
&lt;p&gt;size material color&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;9 leather brown&lt;/p&gt;
&lt;p&gt;10 hemp canvas natural&lt;/p&gt;
&lt;p&gt;11 glass transparent&lt;/p&gt;
&lt;p&gt;Table: Shoes, their sizes, and what they&apos;re made of&lt;/p&gt;
&lt;p&gt;(The above is the caption for the table.) Pandoc also supports
multi-line tables:&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;keyword text&lt;/h2&gt;
&lt;p&gt;red Sunsets, apples, and
other red or reddish
things.&lt;/p&gt;
&lt;p&gt;green Leaves, grass, frogs
and other things it&apos;s
not easy being.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;A horizontal rule follows.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Here&apos;s a definition list:&lt;/p&gt;
&lt;p&gt;apples
: Good for making applesauce.
oranges
: Citrus!
tomatoes
: There&apos;s no &quot;e&quot; in tomatoe.&lt;/p&gt;
&lt;p&gt;Again, text is indented 4 spaces. (Put a blank line between each
term/definition pair to spread things out more.)&lt;/p&gt;
&lt;p&gt;Here&apos;s a &quot;line block&quot;:&lt;/p&gt;
&lt;p&gt;| Line one
| Line too
| Line tree&lt;/p&gt;
&lt;p&gt;and images can be specified like so:&lt;/p&gt;
&lt;p&gt;Inline math equations go in like so: $\omega = d\phi / dt$. Display
math should get its own line and be put in in double-dollarsigns:&lt;/p&gt;
&lt;p&gt;$$I = \int \rho R^{2} dV$$&lt;/p&gt;
&lt;p&gt;And note that you can backslash-escape any punctuation characters
which you wish to be displayed literally, ex.: `foo`, *bar*, etc.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;GitHub repository cards&lt;/h2&gt;
&lt;p&gt;You can add dynamic cards that link to GitHub repositories, on page load, the repository information is pulled from the GitHub API.&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;Fabrizz/MMM-OnSpotify&quot;}&lt;/p&gt;
&lt;p&gt;Create a GitHub repository card with the code &lt;code&gt;::github{repo=&quot;&amp;lt;owner&amp;gt;/&amp;lt;repo&amp;gt;&quot;}&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;::github{repo=&quot;saicaca/fuwari&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Admonitions&lt;/h2&gt;
&lt;p&gt;Following types of admonitions are supported: &lt;code&gt;note&lt;/code&gt; &lt;code&gt;tip&lt;/code&gt; &lt;code&gt;important&lt;/code&gt; &lt;code&gt;warning&lt;/code&gt; &lt;code&gt;caution&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;:::note
Highlights information that users should take into account, even when skimming.
:::&lt;/p&gt;
&lt;p&gt;:::tip
Optional information to help a user be more successful.
:::&lt;/p&gt;
&lt;p&gt;:::important
Crucial information necessary for users to succeed.
:::&lt;/p&gt;
&lt;p&gt;:::warning
Critical content demanding immediate user attention due to potential risks.
:::&lt;/p&gt;
&lt;p&gt;:::caution
Negative potential consequences of an action.
:::&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:::note
Highlights information that users should take into account, even when skimming.
:::

:::tip
Optional information to help a user be more successful.
:::
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The title of the admonition can be customized.&lt;/p&gt;
&lt;p&gt;:::note[MY CUSTOM TITLE]
This is a note with a custom title.
:::&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:::note[MY CUSTOM TITLE]
This is a note with a custom title.
:::&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>Derick</author></item><item><title>迁移博客</title><link>https://blog.ithuo.net/posts/migration-blog-astro/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/migration-blog-astro/</guid><pubDate>Fri, 10 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;ul&gt;
&lt;li&gt;最近看到大家都在用astro重构博客，我也将原来的Hexo博客迁移到&lt;a href=&quot;https://github.com/saicaca/fuwari&quot;&gt;saicaca&lt;/a&gt;基于astro开发的博客中，作者很厉害，实现的效果和代码都很优美。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;::github{repo=&quot;saicaca/fuwari&quot;}&lt;/p&gt;
&lt;h3&gt;Astro 框架有以下几个主要优点:&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;岛屿架构(Island Architecture)和部分水合(Partial Hydration)&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Astro 采用独特的岛屿架构，页面大部分保持静态，只有需要交互的部分(岛屿)才进行水合。&lt;/li&gt;
&lt;li&gt;这种部分水合的方式可以大幅提升网站性能，改善用户体验。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;多框架支持&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Astro 允许在同一项目中无缝集成使用 React、Vue、Svelte 等不同框架编写的组件。&lt;/li&gt;
&lt;li&gt;开发者可以灵活选择熟悉的框架来构建 UI 组件。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;以内容为中心&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Astro 专注于构建内容丰富的静态网站，对博客、文档、作品集等场景特别适合。&lt;/li&gt;
&lt;li&gt;内置了 Markdown、内容集合等功能，方便创作和组织内容。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;出色的开发者体验&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Astro 提供了友好的 API 和工具，如 Astro 开发工具栏方便调试。&lt;/li&gt;
&lt;li&gt;拥有活跃的社区，文档清晰易懂。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;高性能&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;得益于岛屿架构，Astro 构建的网站性能出色，初始加载速度快。SEO友好&lt;/li&gt;
&lt;li&gt;Astro 4.0 将组件渲染性能提升了 30%~75%。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;灵活扩展&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Astro 支持使用 React 等框架编写交互组件，也能集成 Markdown 等内容。&lt;/li&gt;
&lt;li&gt;通过插槽(slot)可以在 .astro 组件中嵌入任意 HTML。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;总之，Astro 独特的架构理念和专注的定位，使其在构建高性能内容网站方面具有明显优势，同时良好的开发体验也是一大亮点。它在静态站点生成器和现代 Web 框架之间找到了很好的平衡。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;原博客UI&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/5ec9d02e5f6b8b6ee88c4ce1087deef8.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;原博客地址：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;::github{repo=&quot;auroral-ui/hexo-theme-aurora&quot;}&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;忙活了一天，终于将博客迁移成功，从notion编写，触发slack，然后调用工作流，执行GitHub Action实现自动发布&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Derick</author></item><item><title>Perplexity system prompt </title><link>https://blog.ithuo.net/posts/perplexity-system-prompt/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/perplexity-system-prompt/</guid><pubDate>Sat, 20 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;看到perplexity放出来的prompt，针对这几大类提问方式，提供基础的建议，测试之后发现对于越确定性的内容，输出的结果越理想&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Assistant Background

You are Perplexity, a helpful search assistant trained by Perplexity AI.

# General Instructions

Write an accurate, detailed, and comprehensive response to the user&apos;&apos;s INITIAL_QUERY.
Additional context is provided as &quot;USER_INPUT&quot; after specific questions.
Your answer should be informed by the provided &quot;Search results&quot;.
Your answer must be precise, of high-quality, and written by an expert using an unbiased and journalistic tone.
Your answer must be written in the same language as the question, even if language preference is different.

You MUST cite the most relevant search results that answer the question. Do not mention any irrelevant results.
You MUST ADHERE to the following instructions for citing search results:
- to cite a search result, enclose its index located above the summary with brackets at the end of the corresponding sentence, for example &quot;Ice is less dense than water.&quot;  or &quot;Paris is the capital of France.&quot;
- NO SPACE between the last word and the citation, and ALWAYS use brackets. Only use this format to cite search results. NEVER include a References section at the end of your answer.
- If you don&apos;t know the answer or the premise is incorrect, explain why.
If the search results are empty or unhelpful, answer the question as well as you can with existing knowledge.

You MUST NEVER use moralization or hedging language. AVOID using the following phrases:
- &quot;It is important to ...&quot;
- &quot;It is inappropriate ...&quot;
- &quot;It is subjective ...&quot;

You MUST ADHERE to the following formatting instructions:
- Use markdown to format paragraphs, lists, tables, and quotes whenever possible.
- Use headings level 2 and 3 to separate sections of your response, like &quot;## Header&quot;, but NEVER start an answer with a heading or title of any kind.
- Use single new lines for lists and double new lines for paragraphs.
- Use markdown to render images given in the search results.
- NEVER write URLs or links.

# Query type specifications

You must use different instructions to write your answer based on the type of the user&apos;s query. However, be sure to also follow the General Instructions, especially if the query doesn&apos;t match any of the defined types below. Here are the supported types.

## Academic Research

You must provide long and detailed answers for academic research queries. 
Your answer should be formatted as a scientific write-up, with paragraphs and sections, using markdown and headings.

## Recent News

You need to concisely summarize recent news events based on the provided search results, grouping them by topics.
You MUST ALWAYS use lists and highlight the news title at the beginning of each list item.
You MUST select news from diverse perspectives while also prioritizing trustworthy sources.
If several search results mention the same news event, you must combine them and cite all of the search results. Prioritize more recent events, ensuring to compare timestamps.
You MUST NEVER start your answer with a heading of any kind.

## Weather

Your answer should be very short and only provide the weather forecast. 
If the search results do not contain relevant weather information, you must state that you don&apos;t have the answer.

## People

You need to write a short biography for the person mentioned in the query. 
If search results refer to different people, you MUST describe each person individually and AVOID mixing their information together.
NEVER start your answer with the person&apos;s name as a header.

## Coding

You MUST use markdown code blocks to write code, specifying the language for syntax highlighting, for example ```bash or ```python
If the user&apos;s query asks for code, you should write the code first and then explain it.

## Cooking Recipes

You need to provide step-by-step cooking recipes, clearly specifying the ingredient, the amount, and precise instructions during each step.

## Translation

If a user asks you to translate something, you must not cite any search results and should just provide the translation.

## Creative Writing

If the query requires creative writing, you DO NOT need to use or cite search results, and you may ignore General Instructions pertaining only to search. You MUST follow the user&apos;s instructions precisely to help the user write exactly what they need. 

## Science and Math

If the user query is about some simple calculation, only answer with the final result.
Follow these rules for writing formulas:
- Always use $$ and$$ for inline formulas and$$ and$$ for blocks, for example$$x^4 = x - 3 $$
- To cite a formula add citations to the end, for example$$ \sin(x) $$  or $$x^2-2$$ .
- Never use $ or $$ to render LaTeX, even if it is present in the user query.
- Never use unicode to render math expressions, ALWAYS use LaTeX.
- Never use the \label instruction for LaTeX.

## URL Lookup

When the user&apos;s query includes a URL, you must rely solely on information from the corresponding search result.
DO NOT cite other search results, ALWAYS cite the first result, e.g. you need to end with.
If the user&apos;s query consists only of a URL without any additional instructions, you should summarize the content of that URL.

## Shopping

If the user query is about shopping for a product, you MUST follow these rules:
- Organize the products into distinct sectors. For example, you could group shoes by style (boots, sneakers, etc.)
- Cite at most 5 search results using the format provided in General Instructions to avoid overwhelming the user with too many options.
None
Current date: 08:18AM Saturday, April 20, 2024
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>Derick</author></item><item><title>Microservices in Data Engineering</title><link>https://blog.ithuo.net/posts/microservices-in-data-engineering/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/microservices-in-data-engineering/</guid><pubDate>Thu, 11 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;介绍&lt;/h3&gt;
&lt;p&gt;在阅读了Daniel Beach的一篇关于在数据工程领域使用微服务的机会的文章(&lt;a href=&quot;https://dataengineeringcentral.substack.com/p/microservices-for-data-engineering&quot;&gt;https://dataengineeringcentral.substack.com/p/microservices-for-data-engineering&lt;/a&gt;)后,我受到启发,分享我在这方面的经验。&lt;/p&gt;
&lt;p&gt;去年,我用Golang开发了自己的Kafka Connect实现,以从许多主题中摄取数据。让我们看看是如何做到的。&lt;/p&gt;
&lt;p&gt;先前解决方案的问题&lt;/p&gt;
&lt;p&gt;技术栈是Azure Eventhub作为消息系统,Kubernetes和Databricks。后端团队有数百个通过Eventhub进行通信的微服务。数据工程团队需要从其中许多微服务中摄取数据。现有的解决方案是使用Eventhub Capture服务,只需几次点击,就可以配置从Eventhub队列到数据湖的数据摄取,并以Avro格式定期存储。&lt;/p&gt;
&lt;p&gt;该解决方案运行良好,但成本高昂,整个公司Eventhub成本的一半是由于捕获服务造成的。而我们甚至还没有开始从吞吐量最高的队列(每天300 GB)中捕获事件。&lt;/p&gt;
&lt;h3&gt;项目需求&lt;/h3&gt;
&lt;p&gt;新的解决方案应该是:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;更便宜&lt;/li&gt;
&lt;li&gt;高效&lt;/li&gt;
&lt;li&gt;标准化且可复制,适用于尽可能多的主题&lt;/li&gt;
&lt;li&gt;易于部署和配置&lt;/li&gt;
&lt;li&gt;易于维护&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我提出的解决方案是用&lt;code&gt;Golang&lt;/code&gt;开发两个模块。一个用于管理&lt;code&gt;Consumer&lt;/code&gt;配置和高级逻辑,另一个用于实现数据摄取逻辑(如将消息批量写入文件,然后确认消息)。然后,我会为每个Eventhub主题部署一个微服务。在每个微服务中,唯一的代码就是导入数据摄取模块并调用摄取启动函数。其余的都是包含Kubernetes、Eventhub、secrets等配置的Yaml文件。因此,要创建和部署一个新的微服务,我只需复制现有的一个,在VS Code中用简单的替换更改配置变量的名称,并在需要时更新Kubernetes的RAM和CPU值。就是这样,在5分钟内我就可以准备好部署它。&lt;/p&gt;
&lt;p&gt;微服务创建的文件格式是包含多行json的Txt。原因是没有使用&lt;code&gt;schema registry&lt;/code&gt;。因此,无法管理模式演化,我们会丢失新字段。将其与&lt;code&gt;schema registry&lt;/code&gt;和&lt;code&gt;parquet&lt;/code&gt;文件格式一起使用,并检查性能,这将是很有趣的。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/53c5a3bc62c02653387f95f07d2b4beb.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;正如我们从架构中可以看到,微服务的作用仅仅是原始数据的纯粹摄取,没有其他功能。这个解决方案使我们的团队能够从Eventhub大规模地持续摄取数据,并在ETL执行频率方面给了我们很大的灵活性。我们每分钟都有数据落地到Azure存储,然后我们使用Databricks的Autoloader对其进行增量加载、转换并准备在Power BI中报告。我们可以近乎实时地运行Databricks管道,或者每天运行一次,根据我们的需要而定。但是成本要低得多,否则我们即使不需要,也不得不使用Eventhub capture或Spark streaming。&lt;/p&gt;
&lt;p&gt;然后,我们开始从接收来自API网关的所有消息的主题中摄取数据,每天300 GB。微服务甚至没有畏缩,它们工作得非常出色。即使其他从未使用过Golang的团队成员也能在几分钟内创建和部署它们。&lt;/p&gt;
&lt;h3&gt;为什么选择Golang?&lt;/h3&gt;
&lt;p&gt;数据工程团队的大多数人主要擅长使用&lt;code&gt;Python&lt;/code&gt;。然而对于这种类型的项目,我认为一种专门为后端和高吞吐量工作负载设计的静态类型语言会是更好的选择。&lt;/p&gt;
&lt;p&gt;后端团队的大多数微服务都是用Java和Golang编写的,所以我决定使用Go。在几周内,我学习了该语言的基础知识,并开始在业余时间尝试这些想法。使用Go而不是Python的另一个优势是,后端团队已经有许多DevOps管道用于测试、检查、构件、部署等(而Python没有)。此外,如果我们遇到紧急情况,公司内部会有必要的技能组合。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>windows 脚本辅助修改hosts</title><link>https://blog.ithuo.net/posts/windows-script-assist-modify-hosts/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/windows-script-assist-modify-hosts/</guid><pubDate>Mon, 01 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在Windows系统的软件中使用代理软件，通常监听127.0.0.1:xxxx固定地址，但如果使用了虚拟机，容器，Linux子系统等支持自定义配置代理的软件后，在配置代理会比较繁琐，所以我试着在hosts文件中配置映射，虚拟域名对应经常变动的ipv4地址，例如192.168.1.65 mylocal.ip，这样其他软件只需要配置一个代理地址 mylocal.ip:port&lt;/p&gt;
&lt;p&gt;由于经常出差，切换网络环境之后，IP网段都会发生变化，所以我需要有个脚本来辅助完成自动修改hosts文件，以便于我的所有软件都可以正常走代理请求&lt;/p&gt;
&lt;p&gt;Windows环境下，最好的脚本语言是powershell，下面我将使用powershell编写脚本来获取IP地址并配置到hosts文件中&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] &apos;Administrator&apos;)) {
    if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) {
        $CommandLine = &quot;-File `&quot;&quot; + $MyInvocation.MyCommand.Path + &quot;`&quot;&quot;
        if ($MyInvocation.UnboundArguments) {
            $CommandLine += &quot; &quot; + $MyInvocation.UnboundArguments
        }
        Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine
        Exit
    }
}
#Start-Process -Verb runAs -FilePath powershell

# 获取无线网卡的IPv4地址
$ip_address = (Get-NetIPAddress -InterfaceAlias &quot;WiFi&quot; -AddressFamily IPv4).IPAddress

# 检查hosts文件中是否已存在&quot;mylocal.ip&quot;的映射,如果存在则更新,否则添加
$hostsFile = &quot;C:\Windows\System32\drivers\etc\hosts&quot;
$linePattern = &quot;mylocal.ip&quot;
$newLine = &quot;$ip_address mylocal.ip&quot;

$hostsContent = Get-Content $hostsFile
$lineExists = $hostsContent | Select-String -Pattern $linePattern -Quiet

if ($lineExists) {
    $updatedContent = $hostsContent | ForEach-Object {
        if ($_ -match $linePattern) {
            $newLine
        } else {
            $_
        }
    }
    Set-Content -Path $hostsFile -Value $updatedContent -Force
    Write-Host &quot;Updated mylocal.ip with IP address $ip_address in hosts file.&quot;
} else {
    Add-Content -Path $hostsFile -Value $newLine
    Write-Host &quot;Added mylocal.ip with IP address $ip_address to hosts file.&quot;
}
# 添加暂停语句以显示输出结果
Read-Host &quot;Press Enter to exit&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;代码的作用会申请管理员权限，并且获取IPv4地址，之后检测hosts文件中是否存在mylocal.ip映射，并进行修改或新增映射&lt;/p&gt;
&lt;p&gt;当切换网络环境后，可以直接执行ps1脚本，就能继续正常使用代理开启畅游。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>HTTPS的工作原理</title><link>https://blog.ithuo.net/posts/know-how-is-https-workflow/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/know-how-is-https-workflow/</guid><pubDate>Fri, 29 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/b160325ccd4929d84c881862b2a61c32.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;HTTPS原理教程&lt;/h2&gt;
&lt;p&gt;HTTPS（HyperText Transfer Protocol Secure）是一种在HTTP基础上增加了加密和认证功能的安全网络传输协议。它通过加密数据传输和验证服务器身份，确保数据在客户端和服务器之间的传输过程中不被窃听和篡改。以下是HTTPS的工作原理及其关键技术的详细解释。&lt;/p&gt;
&lt;h3&gt;1. HTTPS工作流程&lt;/h3&gt;
&lt;p&gt;HTTPS的工作流程可以分为以下几个步骤：&lt;/p&gt;
&lt;h3&gt;1.1 TCP握手&lt;/h3&gt;
&lt;p&gt;在HTTPS连接建立之前，首先需要进行TCP握手。TCP握手的过程如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;客户端向服务器发送一个同步（SYN）请求。&lt;/li&gt;
&lt;li&gt;服务器收到请求后，返回一个同步确认（SYN-ACK）响应。&lt;/li&gt;
&lt;li&gt;客户端收到响应后，再次发送一个确认（ACK）请求，完成握手。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;1.2 证书校验&lt;/h3&gt;
&lt;p&gt;TCP握手完成后，客户端会向服务器发送证书请求，服务器会返回一个数字证书。数字证书包含服务器的公钥和由可信任的证书颁发机构（CA）签名的证书信息。客户端会验证证书的合法性，确保服务器的身份真实可靠。&lt;/p&gt;
&lt;h3&gt;1.3 密钥交换&lt;/h3&gt;
&lt;p&gt;证书校验通过后，客户端和服务器会进行密钥交换。密钥交换的过程如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;客户端生成一个随机的会话密钥，并使用服务器的公钥对其进行加密。&lt;/li&gt;
&lt;li&gt;服务器使用自己的私钥解密会话密钥。&lt;/li&gt;
&lt;li&gt;双方使用这个会话密钥进行后续的数据加密传输。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;1.4 数据传输&lt;/h3&gt;
&lt;p&gt;在密钥交换完成后，客户端和服务器使用协商好的会话密钥对数据进行加密传输。加密的数据通过网络传输，确保数据在传输过程中不被窃听和篡改。&lt;/p&gt;
&lt;h3&gt;2. HTTPS的关键技术&lt;/h3&gt;
&lt;p&gt;HTTPS的安全性依赖于以下几种关键技术：&lt;/p&gt;
&lt;h3&gt;2.1 非对称加密&lt;/h3&gt;
&lt;p&gt;非对称加密使用一对公钥和私钥进行加密和解密。公钥用于加密数据，私钥用于解密数据。非对称加密确保了只有拥有私钥的服务器才能解密客户端发送的加密数据。&lt;/p&gt;
&lt;h3&gt;2.2 对称加密&lt;/h3&gt;
&lt;p&gt;对称加密使用相同的密钥进行加密和解密。HTTPS在密钥交换过程中生成的会话密钥就是对称密钥。对称加密速度快，适合大数据量的加密传输。&lt;/p&gt;
&lt;h3&gt;2.3 数字证书&lt;/h3&gt;
&lt;p&gt;数字证书由可信任的证书颁发机构（CA）签发，包含服务器的公钥和证书信息。客户端通过验证数字证书，确保服务器的身份真实可靠。&lt;/p&gt;
&lt;h3&gt;3. 应用案例&lt;/h3&gt;
&lt;p&gt;为了更好地理解HTTPS的原理，我们可以举一些实际应用中的例子：&lt;/p&gt;
&lt;h3&gt;3.1 在线购物&lt;/h3&gt;
&lt;p&gt;在在线购物网站上，用户需要输入信用卡信息进行支付。通过HTTPS协议，用户的信用卡信息在传输过程中被加密，确保信息不被窃听和篡改，保障用户的支付安全。&lt;/p&gt;
&lt;h3&gt;3.2 在线银行&lt;/h3&gt;
&lt;p&gt;在线银行系统中，用户需要输入账户信息和密码进行登录。通过HTTPS协议，用户的登录信息在传输过程中被加密，确保账户信息的安全，防止黑客攻击。&lt;/p&gt;
&lt;h3&gt;3.3 社交媒体&lt;/h3&gt;
&lt;p&gt;在社交媒体平台上，用户的个人信息和聊天记录需要保护隐私。通过HTTPS协议，用户的个人信息在传输过程中被加密，确保隐私不被泄露。&lt;/p&gt;
&lt;h3&gt;4. 总结&lt;/h3&gt;
&lt;p&gt;HTTPS通过TCP握手、证书校验、密钥交换和数据加密传输，确保了数据在客户端和服务器之间的安全传输。其关键技术包括非对称加密、对称加密和数字证书。通过HTTPS协议，用户可以在网络上安全地进行各种敏感操作，如在线购物、在线银行和社交媒体等。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Solidity 与 Golang：选择区块链开发的最佳语言</title><link>https://blog.ithuo.net/posts/solidity-vs-golang-best-language-for-blockchain-development/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/solidity-vs-golang-best-language-for-blockchain-development/</guid><pubDate>Tue, 26 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;区块链开发是一个充满活力的领域，选择正确的编程语言对任何项目的成功至关重要。在这篇全面的探讨中,我们将深入比较Solidity和Golang,阐明它们在EVM区块链开发中的优势、长处和考虑因素。&lt;/p&gt;
&lt;h3&gt;Solidity:智能合约的基石&lt;/h3&gt;
&lt;p&gt;Solidity是专门为智能合约开发而设计的语言,已经在区块链领域确立了基石地位。让我们深入了解一些关键优势,它们使Solidity成为基于Ethereum项目的首选:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;与Ethereum生态系统的无缝集成Solidity与Ethereum生态系统无缝集成,为开发者提供了一种专用语言,用于在智能合约中表达复杂的业务逻辑。它与Ethereum Virtual Machine(EVM)的兼容性确保了广泛的可用性。&lt;/li&gt;
&lt;li&gt;内置安全特性安全性是区块链开发中的首要关注点。Solidity通过内置的安全特性来解决这一问题,如函数修饰符、访问控制和异常处理,减轻了可能危及智能合约完整性的常见漏洞。&lt;/li&gt;
&lt;li&gt;智能合约兼容性Solidity的语法专门针对智能合约的独特要求,允许开发者以简洁易读的方式表达复杂的规则和条件。这有助于创建健壮高效的去中心化应用。&lt;/li&gt;
&lt;li&gt;庞大的开发者社区蓬勃发展的开发者社区证明了该语言的普及和可持续性。Solidity开发者受益于大量资源、教程和库,促进了社区内的协作和知识共享。&lt;/li&gt;
&lt;li&gt;经过审计的合约在区块链开发中,安全审计的重要性怎么强调都不为过。Solidity智能合约经过严格的审计过程,确保它们符合高标准的可靠性,并能抵御潜在漏洞。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;虽然Solidity是智能合约开发的强大工具,但它确实面临一些挑战,包括对不熟悉区块链的开发者来说学习曲线较陡,以及在复杂智能合约实现中存在安全性和可靠性方面的担忧。&lt;/p&gt;
&lt;h3&gt;Golang (Go)：增强区块链的可扩展性&lt;/h3&gt;
&lt;p&gt;相比之下,由Google开发的Golang以其卓越的性能和效率而著称,使其成为需要可扩展性和高吞吐量的区块链应用的诱人选择。以下是在区块链开发中使用Golang的一些主要优势:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;性能
Golang以其出色的性能而闻名,非常适合高吞吐量的区块链网络。这种效率对于需要低延迟和快速交易处理的应用程序至关重要。&lt;/li&gt;
&lt;li&gt;并发性
Go内置的并发原语,如goroutines和channels,有助于开发并发和并行代码]。这对于构建可扩展的区块链应用尤其有利,因为高效处理多个任务是必不可少的。&lt;/li&gt;
&lt;li&gt;丰富的标准库
Golang拥有丰富的标准库,涵盖了广泛的任务,减少了对外部依赖的需求。这种对网络、加密和并发编程的全面支持简化了开发过程。&lt;/li&gt;
&lt;li&gt;跨平台兼容性
Go对跨平台开发的原生支持确保应用程序可以在不同的操作系统和架构上无缝运行,提供了部署的灵活性。&lt;/li&gt;
&lt;li&gt;易于部署
Golang的静态链接和简单的部署模型简化了部署过程。开发人员可以将其应用程序打包成具有最少外部依赖的独立可执行文件,从而提高了易用性。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;然而,Golang并非没有挑战。对于从动态或脚本语言转换过来的开发人员来说,其学习曲线和冗长性可能会在某些情况下造成障碍。&lt;/p&gt;
&lt;p&gt;尽管存在这些挑战,但Golang的性能、并发支持和简单性使其成为区块链开发的强大语言选择。其高效性和可扩展性非常适合构建能够满足去中心化网络需求的高性能区块链应用。&lt;/p&gt;
&lt;h3&gt;选择合适的工具&lt;/h3&gt;
&lt;p&gt;在Solidity和Golang之间做出选择时,开发人员必须仔细考虑几个因素:&lt;/p&gt;
&lt;p&gt;目标区块链平台
Solidity和Golang的选择取决于目标区块链平台。Solidity仍然是基于以太坊项目的首选语言,而Golang在需要高性能和可扩展性的场景中大放异彩。&lt;/p&gt;
&lt;p&gt;项目复杂性
手头项目的复杂性起着至关重要的作用。Solidity是为智能合约开发量身定制的,适用于具有复杂业务逻辑的去中心化应用。另一方面,Golang擅长构建智能合约领域之外的可扩展应用。&lt;/p&gt;
&lt;p&gt;性能要求
性能考虑是至关重要的。Solidity与EVM的集成确保了与以太坊的兼容性,而Golang的效率使其成为高性能区块链应用的有力竞争者。&lt;/p&gt;
&lt;p&gt;开发人员专业知识
开发团队的专业知识也会影响选择。如果团队精通Solidity和以太坊生态系统,坚持使用Solidity可能是合乎逻辑的选择。相反,如果重点是可扩展性和性能,Golang可能更合适。&lt;/p&gt;
&lt;h3&gt;结论&lt;/h3&gt;
&lt;p&gt;总之,Solidity和Golang都有独特的优缺点,使它们更适合区块链开发领域中的特定用例。Solidity擅长智能合约和基于以太坊的dApp领域,利用其与以太坊生态系统的无缝集成和强大的安全特性。另一方面,Golang使开发人员能够在智能合约范围之外构建可扩展和高性能的区块链应用。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>How To Become an expert in Web3 technologies (Ethereum, IPFS, Solidity)</title><link>https://blog.ithuo.net/posts/how-to-become-an-expert-in-web3-technologies-ethereum-ipfs-solidity/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/how-to-become-an-expert-in-web3-technologies-ethereum-ipfs-solidity/</guid><pubDate>Sun, 24 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;&lt;strong&gt;Introduction to Web3 Technologies&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Web3 is the next generation of the internet, also known as the decentralized web, that is powered by blockchain technology. It is a term used to describe the vision of a decentralized and censorship-resistant internet.&lt;/p&gt;
&lt;p&gt;The web we currently use (Web 2.0) is built on centralized servers owned by large corporations and governments, making it vulnerable to censorship, surveillance, and control. Web3, on the other hand, is built on top of decentralized networks, such as Ethereum, which enables users to interact directly with each other without the need for intermediaries.&lt;/p&gt;
&lt;p&gt;One of the key technologies that power Web3 is Ethereum, a decentralized blockchain platform that allows developers to build decentralized applications (DApps). Ethereum uses smart contracts, which are self-executing pieces of code that automate the execution of agreements between parties. This enables developers to create applications that are decentralized, secure, and transparent.&lt;/p&gt;
&lt;p&gt;Another important technology in the Web3 ecosystem is the InterPlanetary File System (IPFS). It is a decentralized file storage and sharing system that uses a peer-to-peer network. IPFS allows for the storage of files across multiple nodes, making it secure, fault-tolerant, and censorship-resistant.&lt;/p&gt;
&lt;p&gt;Solidity is the programming language used to develop smart contracts on the Ethereum blockchain. It is designed to be secure and easy to use, enabling developers to create complex applications and execute transactions on the blockchain.&lt;/p&gt;
&lt;p&gt;The combination of these technologies is revolutionizing the internet and creating a more decentralized and transparent ecosystem. Some of the key benefits of Web3 technologies include:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Decentralization: With Web3, there is no central authority controlling the internet. This makes it harder for governments and corporations to censor or manipulate information.&lt;/li&gt;
&lt;li&gt;Security: The use of blockchain technology in Web3 makes it more secure as the data is stored and verified across a network of nodes, making it difficult for hackers to change or manipulate.&lt;/li&gt;
&lt;li&gt;Transparency: The use of smart contracts and decentralized networks improves transparency as all transactions and data are publicly available and can be easily audited.&lt;/li&gt;
&lt;li&gt;Privacy: Web3 technologies offer better privacy protection as users have full control over their data and can choose to be anonymous while using decentralized applications.&lt;/li&gt;
&lt;li&gt;Cost-effective: Web3 eliminates the need for intermediaries, which can significantly reduce transaction costs, making it more cost-effective for users.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;&lt;strong&gt;Understanding Ethereum&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Ethereum is a decentralized open-source platform that runs smart contracts. It was proposed by Vitalik Buterin in 2013 and launched in 2015. Ethereum enables developers to build and deploy decentralized applications (Dapps) on its blockchain. It also has a cryptocurrency called Ether (ETH) which is used to pay for transactions and incentivize miners.&lt;/p&gt;
&lt;p&gt;One of the key components of Ethereum is the Ethereum Virtual Machine (EVM). EVM is a runtime environment that executes smart contracts written in Solidity, the programming language of Ethereum. It is a Turing complete machine, which means that it can compute any programmatic function, making it the backbone of the Ethereum network.&lt;/p&gt;
&lt;p&gt;Smart contracts are self-executing immutable pieces of code that exist on the blockchain and can be triggered by specific events. They allow for the creation of trustless and tamper-proof agreements between different parties. In Ethereum, smart contracts are stored on the blockchain and can be accessed by anyone.&lt;/p&gt;
&lt;p&gt;The Ethereum network is made up of nodes, where each node is connected to every other node in the network. Nodes maintain a copy of the blockchain and are responsible for validating transactions, executing smart contracts, and keeping the network secure. New blocks are added to the blockchain through a consensus mechanism called Proof of Work (PoW), where miners compete to solve complex mathematical problems to add a block and receive a reward in Ether.&lt;/p&gt;
&lt;p&gt;In 2021, Ethereum is transitioning to a Proof of Stake (PoS) consensus mechanism, where instead of mining, validators stake their Ether to secure the network and in return receive transaction fees. This is known as the Ethereum 2.0 upgrade and is expected to make the network more scalable and energy-efficient.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Exploring IPFS (InterPlanetary File System)&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;IPFS (InterPlanetary File System) is a peer-to-peer distributed file system that aims to change the way files are stored, shared, and accessed on the internet. It is a new protocol based on a decentralized approach to storing and sharing data. Unlike traditional HTTP, IPFS does not rely on a central server or location for data storage and retrieval. Instead, it uses a network of interconnected nodes to store and distribute data.&lt;/p&gt;
&lt;p&gt;IPFS utilizes a content-addressed system, where files are identified by their unique content rather than their location. This means that the content of a file is used to generate a unique hash, which is then used as the file’s address. When a file is requested, the IPFS network uses this address to retrieve the file from any node that has a copy of it. This decentralized approach provides several advantages over traditional HTTP-based systems.&lt;/p&gt;
&lt;p&gt;One of the main advantages of IPFS is its resilience and fault tolerance. Since files are distributed across multiple nodes, the failure of one or more nodes does not affect the availability of the file. This makes it more reliable and less prone to data loss compared to traditional centralized systems.&lt;/p&gt;
&lt;p&gt;Another advantage of IPFS is its efficiency in data transfer. In traditional HTTP, every time a file is downloaded, it is transferred from the remote server to the user’s computer. This can be slow and inefficient, especially for large files. In IPFS, once a file is downloaded, it is cached locally by the node, making subsequent requests for the same file faster and more efficient.&lt;/p&gt;
&lt;p&gt;Data storage and retrieval in IPFS is based on DHT (Distributed Hash Table) technology. DHT allows for efficient data storage and retrieval by distributing the responsibility of managing data across the network. This also helps in load balancing and ensures that no single node becomes overloaded.&lt;/p&gt;
&lt;p&gt;IPFS is also highly secure as all data is encrypted and verified by default. Since files are identified by a unique hash, it is impossible to tamper with the contents of a file without changing its address. Additionally, the use of public-key cryptography ensures that data is only accessible to authorized users.&lt;/p&gt;
&lt;p&gt;IPFS has gained popularity in the decentralized application (Dapp) space as it provides an ideal storage and distribution solution for Dapps. Developers can integrate IPFS into their decentralized applications to store and retrieve data, making them less reliant on central servers. This leads to a more resilient, faster, and more secure Dapp ecosystem.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Getting Started with Solidity&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Solidity is a high-level programming language specifically designed for writing smart contracts on the Ethereum blockchain. It is a statically typed, contract-oriented, and object-oriented language that enables developers to write complex and secure decentralized applications (DApps).&lt;/p&gt;
&lt;p&gt;One of the main advantages of Solidity is its ability to create self-executing smart contracts that run on the Ethereum Virtual Machine (EVM). These smart contracts can hold and transfer value and function as a set of rules for interactions between different parties. Solidity was heavily influenced by C++, Python, and JavaScript, making it easy for developers familiar with these languages to learn and write code in Solidity.&lt;/p&gt;
&lt;p&gt;Structure and Syntax of Solidity:&lt;/p&gt;
&lt;p&gt;A Solidity code is structured as a series of contracts, each with its own variables, functions, and data storage. Contracts are similar to classes in object-oriented programming and they can interact with each other through inheritances, function calls, and events.&lt;/p&gt;
&lt;p&gt;Solidity uses a syntax similar to C++ or JavaScript, with curly braces indicating code blocks and semicolons used to end lines. The main data types in Solidity include boolean, integer, string, address, and array.&lt;/p&gt;
&lt;p&gt;Writing and deploying smart contracts using Solidity:&lt;/p&gt;
&lt;p&gt;To write and deploy a smart contract using Solidity, follow these steps&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set up the development environment: Install the Ethereum client, such as Ganache or Geth, and a code editor that supports Solidity, such as Remix or Visual Studio Code.&lt;/li&gt;
&lt;li&gt;Write the code: Use the Solidity syntax to write your smart contract code. Pay attention to data types, variables, and functions as they are crucial to the functionality and security of your smart contract.&lt;/li&gt;
&lt;li&gt;Test the code: Use a test framework, such as Mocha or Truffle, to test your smart contract code before deploying it on the main network. This will help catch any bugs or vulnerabilities in the code.&lt;/li&gt;
&lt;li&gt;Deploy the contract: Use a development tool, such as Truffle or Remix, to deploy the smart contract on the Ethereum network. This will trigger a transaction that will create an instance of your deployed contract on the blockchain.&lt;/li&gt;
&lt;li&gt;Interact with the contract: Once your contract is deployed, you can interact with it using various blockchain technologies, such as web3.js or the Ethereum Virtual Machine (EVM).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Best practices for developing secure and efficient smart contracts:&lt;/p&gt;
&lt;p&gt;To ensure the security and efficiency of your smart contracts, consider following these best practices&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Thoroughly test your code: As mentioned earlier, testing your code is crucial to catch any bugs or vulnerabilities before deploying it to the main network. Use a test framework and simulate various scenarios to ensure your contract functions as intended.&lt;/li&gt;
&lt;li&gt;Use safe math operations: Integer operations can be susceptible to overflow or underflow, which can lead to unexpected results in your smart contract. Use safe math libraries, such as OpenZeppelin’s SafeMath, to prevent these errors.&lt;/li&gt;
&lt;li&gt;Limit external interactions: Smart contracts are immutable, meaning they cannot be modified after they are deployed. Therefore, it is crucial to minimize external interactions, such as calling external contracts or making API calls, to limit the possibility of any unexpected changes or failures in your contract.&lt;/li&gt;
&lt;li&gt;Document your code: Solidity code can quickly become complex and difficult to understand. It is essential to document your code thoroughly so that others can easily understand its functionality and purpose.&lt;/li&gt;
&lt;li&gt;Follow best coding practices: Use descriptive and meaningful variable and function names, follow appropriate indentation and formatting, and avoid using global variables to ensure your code is easily readable and maintainable.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;&lt;strong&gt;Building Decentralized Applications (DApps)&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;DApps, or decentralized applications, are digital platforms that operate on a decentralized network such as the blockchain. They have gained popularity in recent years due to their unique benefits and capabilities compared to traditional centralized applications.&lt;/p&gt;
&lt;p&gt;Benefits of DApps include:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Decentralization: DApps are not owned or controlled by a single entity, making them resistant to censorship and tampering. This means that users have full control over their data and are not dependent on a central authority to operate the application.&lt;/li&gt;
&lt;li&gt;Transparency: The blockchain, which serves as the underlying technology for DApps, is a transparent and immutable ledger. This means that all transactions and data on the DApp can be publicly viewed and verified, promoting trust and accountability.&lt;/li&gt;
&lt;li&gt;Security: DApps are highly secure due to their decentralized nature and use of advanced cryptographic techniques. Transactions on the blockchain cannot be altered or reversed, and users have full control over their private keys, making it almost impossible for hackers to compromise the system.&lt;/li&gt;
&lt;li&gt;Cost-effective: Since DApps do not require a central authority, they eliminate the need for intermediaries, reducing operational costs. Transaction fees are also relatively low, making DApps more cost-effective than traditional applications.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Designing User Interfaces for DApps:&lt;/p&gt;
&lt;p&gt;Designing user interfaces for DApps should be done with careful consideration of both the technical and user experience (UX) aspects. Some key elements to consider include:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Simple and intuitive design: DApps should have a simple and user-friendly design that makes it easy for users to understand and navigate the application. The interface should also be intuitive, allowing users to easily perform desired actions.&lt;/li&gt;
&lt;li&gt;Integration with blockchain: Since DApps operate on the blockchain, the interface should have features that allow users to interact with the blockchain, such as displaying transaction history and wallet balances.&lt;/li&gt;
&lt;li&gt;Security: The design should incorporate security features such as two-factor authentication and secure login to protect user data and assets.&lt;/li&gt;
&lt;li&gt;Compatibility: DApps should be designed to be accessible on different devices and browsers, ensuring compatibility for a wider user base.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Interacting with Ethereum blockchain using Web3.js library:&lt;/p&gt;
&lt;p&gt;Web3.js is a JavaScript library that allows developers to interact with the Ethereum blockchain. It provides a simple and seamless way to communicate with the blockchain, enabling the creation of DApps. Some key functions of Web3.js include&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Connecting to the blockchain: Web3.js allows developers to connect to the blockchain via an API, allowing them to access data and send transactions.&lt;/li&gt;
&lt;li&gt;Handling authentication and encryption: Web3.js supports multiple authentication and encryption methods, ensuring secure communication with the blockchain.&lt;/li&gt;
&lt;li&gt;Smart Contracts: Web3.js provides a way for developers to interact with smart contracts, including deploying and executing them.&lt;/li&gt;
&lt;li&gt;Account management: Web3.js enables developers to manage user accounts, such as creating new accounts and sending transactions from specific accounts.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Testing and Deploying DApps on the Ethereum network:&lt;/p&gt;
&lt;p&gt;Before deploying a DApp on the Ethereum network, it is important to thoroughly test the application to ensure its functionality and security. Some common testing methods include&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Unit testing: This involves testing each unit or component of the DApp individually to identify and fix any bugs or issues.&lt;/li&gt;
&lt;li&gt;Integration testing: This tests the interaction between different components of the DApp to ensure they work together as intended.&lt;/li&gt;
&lt;li&gt;User acceptance testing: This type of testing involves getting feedback from targeted users to identify any usability issues or suggestions for improvement.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once the DApp has been thoroughly tested, it can be deployed on the Ethereum network using tools such as Truffle or Remix. The deployment process involves deploying the smart contracts, configuring the DApp’s front-end to connect to the blockchain, and publishing the DApp on a network such as the Ethereum mainnet or testnet.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Advanced Topics in Web3 Technologies&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Decentralized Finance (DeFi) is a term used to describe the use of decentralized networks and blockchain technology to create a new financial system that is open, permissionless, and transparent. The goal of DeFi is to eliminate intermediaries and create a more efficient, inclusive, and secure financial system.&lt;/p&gt;
&lt;p&gt;One of the main benefits of DeFi is its ability to provide financial services to anyone with an internet connection, regardless of their location or financial status. Traditional financial services often exclude certain individuals or require high fees, making it difficult for people to access financial services. DeFi, on the other hand, allows anyone with an internet connection to participate in the financial system, whether it’s through lending, borrowing, trading, or other services.&lt;/p&gt;
&lt;p&gt;Some of the popular DeFi applications include decentralized exchanges, lending and borrowing platforms, stablecoins, and prediction markets. These applications are built on open-source protocols and run on decentralized networks, making them accessible and transparent to anyone.&lt;/p&gt;
&lt;p&gt;Another important aspect of Web3 is Non-Fungible Tokens (NFTs), which are unique digital assets that are indivisible and cannot be replicated. NFTs have gained popularity in recent years, especially within the art and gaming industries, as they provide a way to verify ownership and scarcity of digital assets. NFTs are also being explored for their potential use in DeFi, allowing for the creation of unique and scarce financial instruments.&lt;/p&gt;
&lt;p&gt;However, one of the challenges faced by the DeFi and NFT space is scalability. As more users and applications join the decentralized ecosystem, the strain on blockchain networks such as Ethereum increases. This has led to the development of Layer 2 scaling solutions, which are additional protocols built on top of Ethereum to increase its capacity and speed. These solutions aim to address the scalability issues of the Ethereum network, making it possible for more transactions to be processed at a lower cost.&lt;/p&gt;
&lt;p&gt;In the future, we can expect to see further developments and advancements in the Web3 ecosystem. This may include the integration of artificial intelligence (AI) and the Internet of Things (IoT) with blockchain technology, creating even more efficient and autonomous systems. Additionally, we may see the emergence of cross-chain communication protocols, allowing for interoperability between different blockchains and further expanding the capabilities of DeFi and NFTs.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Case Studies and Real-World Examples&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;CryptoKitties: This popular gaming DApp built on Ethereum allows users to collect, breed, and trade virtual cats. It showcases the use case of Ethereum for creating virtual assets and creating a unique gaming experience.&lt;/li&gt;
&lt;li&gt;Augur: This decentralized prediction market platform based on Ethereum allows users to bet on the outcome of real-world events. It highlights the use of smart contracts to create trustless betting systems.&lt;/li&gt;
&lt;li&gt;Peepeth: This social media platform built on Ethereum and IPFS ensures data integrity and censorship resistance. It showcases the potential of blockchain technology to disrupt traditional social media platforms.&lt;/li&gt;
&lt;li&gt;Golem: This DApp utilizes a decentralized network to provide users with computing power for tasks such as rendering 3D images or machine learning. It demonstrates the use of blockchain for decentralized cloud computing.&lt;/li&gt;
&lt;li&gt;Brave Browser: Built with blockchain-based advertising technology, this browser allows content creators to be directly rewarded by their audience, bypassing intermediaries and ad blockers. It showcases the use case of blockchain in disrupting the advertising industry.&lt;/li&gt;
&lt;li&gt;Civil: A decentralized journalism platform built on Ethereum and IPFS, Civil aims to provide a sustainable model for trustworthy, unbiased journalism. It demonstrates the potential of blockchain to promote transparency and combat fake news.&lt;/li&gt;
&lt;li&gt;Provenance: This DApp utilizes blockchain technology to track the supply chain of products, ensuring transparency and authenticity. It is used by companies in the food, fashion, and jewelry industries to provide customers with verifiable information about the origin of their products.&lt;/li&gt;
&lt;li&gt;MindSports: This platform uses Ethereum and Solidity to create a decentralized marketplace for online board games, allowing players to compete and trade in a trustless manner. It showcases the use of blockchain in the gaming industry.&lt;/li&gt;
&lt;li&gt;Gitcoin: This DApp utilizes blockchain for a decentralized freelance marketplace, where developers can get rewarded for their contributions to open-source projects. It highlights the potential of blockchain to disrupt traditional freelancer platforms.&lt;/li&gt;
&lt;li&gt;MakerDAO: This DApp built on Ethereum allows users to generate stablecoins (DAI) by collateralizing their Ethereum assets. It demonstrates the potential of blockchain for creating a stable and decentralized financial system.&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><author>Derick</author></item><item><title>猎豹敏捷研发模式:追求速度与灵活性的极致</title><link>https://blog.ithuo.net/posts/cheetah-agile-development-model-pursuing-ultimate-speed-and-flexibility/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/cheetah-agile-development-model-pursuing-ultimate-speed-and-flexibility/</guid><pubDate>Mon, 18 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;猎豹敏捷研发模式是一种追求极致速度和灵活性的敏捷开发方法,适用于快速变化的市场环境和创新型项目。&lt;/p&gt;
&lt;h2&gt;1. 核心理念&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;速度至上:以最快速度响应市场需求和用户反馈&lt;/li&gt;
&lt;li&gt;持续创新:鼓励试错和快速迭代&lt;/li&gt;
&lt;li&gt;精益团队:保持小规模、高效的团队结构&lt;/li&gt;
&lt;li&gt;灵活适应:随时调整方向,拥抱变化&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;2. 主要特点&lt;/h2&gt;
&lt;h3&gt;超短迭代周期&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;采用1-2周的超短Sprint&lt;/li&gt;
&lt;li&gt;每日甚至每半天进行产品评审和调整&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;最小可行产品(MVP)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;快速构建MVP验证想法&lt;/li&gt;
&lt;li&gt;持续收集用户反馈并迭代&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;扁平化沟通&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;减少层级,促进信息快速流动&lt;/li&gt;
&lt;li&gt;团队成员直接与用户沟通&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;自组织团队&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;赋予团队更多自主权&lt;/li&gt;
&lt;li&gt;鼓励成员多角色转换&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;持续集成/持续部署(CI/CD)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;自动化构建、测试、部署流程&lt;/li&gt;
&lt;li&gt;支持随时发布新版本&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;实时数据分析&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;实时监控用户行为数据&lt;/li&gt;
&lt;li&gt;快速调整产品策略&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3. 实施步骤&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;组建小型跨职能团队(5-9人)&lt;/li&gt;
&lt;li&gt;制定清晰的产品愿景和目标&lt;/li&gt;
&lt;li&gt;规划短期迭代(1-2周)&lt;/li&gt;
&lt;li&gt;每日站会同步进度(15分钟以内)&lt;/li&gt;
&lt;li&gt;频繁与用户沟通,收集反馈&lt;/li&gt;
&lt;li&gt;快速原型验证,持续迭代&lt;/li&gt;
&lt;li&gt;自动化测试和部署&lt;/li&gt;
&lt;li&gt;实时监控数据,及时调整&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;4. 适用场景&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;创新型产品开发&lt;/li&gt;
&lt;li&gt;市场需求快速变化的领域&lt;/li&gt;
&lt;li&gt;初创公司或创新部门&lt;/li&gt;
&lt;li&gt;需要快速验证商业模式的项目&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;5. 优势与挑战&lt;/h2&gt;
&lt;p&gt;优势:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;极快的市场响应速度&lt;/li&gt;
&lt;li&gt;高度的灵活性和适应性&lt;/li&gt;
&lt;li&gt;促进创新和试错精神&lt;/li&gt;
&lt;li&gt;提高团队积极性和主动性&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;挑战:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可能牺牲部分代码质量和文档完整性&lt;/li&gt;
&lt;li&gt;需要团队具备较高的自主能力&lt;/li&gt;
&lt;li&gt;可能导致频繁的方向调整&lt;/li&gt;
&lt;li&gt;不适合大规模或复杂系统开发&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;结语&lt;/h2&gt;
&lt;p&gt;猎豹敏捷研发模式以其极致的速度和灵活性,特别适合在快速变化的市场环境中进行创新型产品开发。然而,它也对团队能力和组织文化提出了较高要求。在实施过程中,需要根据具体项目和团队特点进行适当调整,找到速度、质量和可持续性之间的平衡。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 70 of learning English</title><link>https://blog.ithuo.net/posts/day-70-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-70-of-learning-english/</guid><pubDate>Thu, 08 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dear Derick,&lt;/p&gt;
&lt;p&gt;On the fourth day of your eleventh week, let&apos;s focus on integrating your learning into daily life activities and enhancing your ability to navigate everyday situations in English. This will involve learning vocabulary related to shopping, dining, and transportation, and practicing these in mock scenarios.&lt;/p&gt;
&lt;h3&gt;Thursday:&lt;/h3&gt;
&lt;h3&gt;Morning:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Learn Vocabulary:&lt;/strong&gt; Focus on vocabulary related to daily life activities. This includes words and phrases for shopping (e.g., &quot;checkout,&quot; &quot;discount,&quot; &quot;receipt&quot;), dining (e.g., &quot;reservation,&quot; &quot;menu,&quot; &quot;service charge&quot;), and transportation (e.g., &quot;public transit,&quot; &quot;fare,&quot; &quot;schedule&quot;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Contextual Sentences:&lt;/strong&gt; Create sentences using the new vocabulary to understand their usage better. For example, &quot;Could I have the menu, please?&quot; or &quot;What time does the next bus arrive?&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Afternoon:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mock Scenarios:&lt;/strong&gt; Participate in role-playing exercises that simulate real-life situations, such as buying groceries, ordering food in a restaurant, or asking for directions. This will help you practice conversational English in a controlled environment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conversation Practice:&lt;/strong&gt; Have a free conversation with me or a study partner, trying to incorporate as many of the new words and phrases as possible. This could be a simulated dialogue about planning a day out, including shopping, dining, and using public transportation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification of Study Results:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Role-Playing Feedback:&lt;/strong&gt; After the role-playing exercises, we&apos;ll discuss your performance, focusing on pronunciation, vocabulary usage, and how naturally you navigated the scenarios.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vocabulary Quiz:&lt;/strong&gt; A short quiz on the day&apos;s vocabulary to ensure retention and understanding.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This day&apos;s focus on daily life activities will not only enhance your vocabulary but also your confidence in using English in everyday contexts. Remember, the key to language learning is practice, so try to immerse yourself in these scenarios as much as possible.&lt;/p&gt;
&lt;p&gt;Certainly, Derick. Here are example sentences using vocabulary related to shopping, dining, and transportation:&lt;/p&gt;
&lt;h3&gt;Shopping&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Checkout:&lt;/strong&gt; &quot;I found everything I needed and headed to the checkout counter to pay for my groceries.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Discount:&lt;/strong&gt; &quot;The store offered a 20% discount on all clothing items during the holiday sale.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Receipt:&lt;/strong&gt; &quot;Could you please provide me with the receipt in case I need to return this item?&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Dining&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reservation:&lt;/strong&gt; &quot;I made a dinner reservation for two at our favorite Italian restaurant.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Menu:&lt;/strong&gt; &quot;The waiter brought the menu, and the seafood options looked particularly appetizing.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Service Charge:&lt;/strong&gt; &quot;The bill includes a service charge, so we don&apos;t need to leave an additional tip.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Transportation&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Public Transit:&lt;/strong&gt; &quot;I use public transit to commute to work every day because it&apos;s more environmentally friendly.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fare:&lt;/strong&gt; &quot;The fare for the subway ride is $2.50, regardless of the distance traveled.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Schedule:&lt;/strong&gt; &quot;I checked the bus schedule to ensure I arrive at the station on time.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These sentences incorporate the vocabulary into everyday contexts, helping you understand how they are used in real-life situations. Practice creating your own sentences as well to further enhance your learning.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.wikihow.com/Study-a-Week-Before-an-Exam&quot;&gt;https://www.wikihow.com/Study-a-Week-Before-an-Exam&lt;/a&gt;
[2] &lt;a href=&quot;https://www.youtube.com/watch?v=7EJOs4AeQGk&quot;&gt;https://www.youtube.com/watch?v=7EJOs4AeQGk&lt;/a&gt;
[3] &lt;a href=&quot;https://www.princetonreview.com/college-advice/back-to-school-study-tips&quot;&gt;https://www.princetonreview.com/college-advice/back-to-school-study-tips&lt;/a&gt;
[4] &lt;a href=&quot;https://shorelight.com/student-stories/21-best-study-tips-for-final-exams/&quot;&gt;https://shorelight.com/student-stories/21-best-study-tips-for-final-exams/&lt;/a&gt;
[5] &lt;a href=&quot;https://www.teacherspayteachers.com/Product/Vocabulary-Word-Study-Word-of-the-Week-Weeks-11-20-1496594&quot;&gt;https://www.teacherspayteachers.com/Product/Vocabulary-Word-Study-Word-of-the-Week-Weeks-11-20-1496594&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 69 of learning English</title><link>https://blog.ithuo.net/posts/day-69-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-69-of-learning-english/</guid><pubDate>Wed, 07 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dear Derick,&lt;/p&gt;
&lt;p&gt;On the third day of your eleventh week, you should focus on improving your listening comprehension skills and writing in English. Here&apos;s your plan for the day:&lt;/p&gt;
&lt;h3&gt;Wednesday:&lt;/h3&gt;
&lt;h3&gt;Morning:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Listening Practice:&lt;/strong&gt; Listen to English podcasts or watch videos on topics of personal interest. This will help you improve your comprehension and familiarize yourself with different accents and speaking speeds.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Note-Taking:&lt;/strong&gt; While listening, take notes on new vocabulary or phrases you come across. Try to understand them from the context or look them up later.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Afternoon:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Writing Practice:&lt;/strong&gt; Write a short essay on a technological topic. This could be about a recent development in software technology, a review of a tech product, or a prediction about future tech trends.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review and Feedback:&lt;/strong&gt; Submit your essay to me for review. I will provide feedback on your grammar, vocabulary usage, and overall structure.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification of Study Results:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Listening Comprehension Quiz:&lt;/strong&gt; I may quiz you on the content of the podcasts or videos you listened to in the morning to assess your comprehension.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Writing Review:&lt;/strong&gt; We will go over the feedback on your essay together, discussing areas of improvement and strategies for enhancing your writing skills.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember, improving your listening and writing skills is crucial for achieving fluency in English. Make sure to practice these skills regularly and incorporate the feedback you receive into your future practice.&lt;/p&gt;
&lt;p&gt;Best regards,
Professor Judy&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.wikihow.com/Study-a-Week-Before-an-Exam&quot;&gt;https://www.wikihow.com/Study-a-Week-Before-an-Exam&lt;/a&gt;
[2] &lt;a href=&quot;https://www.youtube.com/watch?v=7EJOs4AeQGk&quot;&gt;https://www.youtube.com/watch?v=7EJOs4AeQGk&lt;/a&gt;
[3] &lt;a href=&quot;https://www.teacherspayteachers.com/Product/Vocabulary-Word-Study-Word-of-the-Week-Weeks-11-20-1496594&quot;&gt;https://www.teacherspayteachers.com/Product/Vocabulary-Word-Study-Word-of-the-Week-Weeks-11-20-1496594&lt;/a&gt;
[4] &lt;a href=&quot;https://www.essentialenglish.review/apps/barrons-1100-words-you-need-to-know/week-11-day-3/&quot;&gt;https://www.essentialenglish.review/apps/barrons-1100-words-you-need-to-know/week-11-day-3/&lt;/a&gt;
[5] &lt;a href=&quot;https://shorelight.com/student-stories/21-best-study-tips-for-final-exams/&quot;&gt;https://shorelight.com/student-stories/21-best-study-tips-for-final-exams/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 68 of learning English</title><link>https://blog.ithuo.net/posts/day-68-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-68-of-learning-english/</guid><pubDate>Tue, 06 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dear Derick,&lt;/p&gt;
&lt;p&gt;On the second day of your eleventh week, you should focus on expanding your vocabulary related to technology, particularly software and hardware terms, and engage in a conversation with me about recent developments in software technology. Here&apos;s your plan for the day:&lt;/p&gt;
&lt;h3&gt;Tuesday:&lt;/h3&gt;
&lt;h3&gt;Morning:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Study Vocabulary:&lt;/strong&gt; Learn specific terms related to software technology, such as &quot;programming,&quot; &quot;application,&quot; &quot;operating system,&quot; &quot;user interface,&quot; and &quot;database.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practice Usage:&lt;/strong&gt; Use these terms in sentences to understand their context and meaning.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Afternoon:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Engage in Conversation:&lt;/strong&gt; Have a discussion with me about recent developments in software technology. This could include topics like new software releases, updates to existing platforms, or trends in the tech industry.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Apply Vocabulary:&lt;/strong&gt; Make sure to incorporate the vocabulary you learned in the morning into our conversation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification of Study Results:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Conversation Review:&lt;/strong&gt; After our discussion, we will review the conversation to assess your use of the new vocabulary and to provide feedback on areas for improvement.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vocabulary Quiz:&lt;/strong&gt; I may quiz you on the meanings of the terms you&apos;ve learned to ensure retention and understanding.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember to schedule your study sessions throughout the day and avoid distractions to maximize your learning efficiency. Consistent review and practical application of vocabulary in conversation will help solidify your knowledge and improve your fluency.&lt;/p&gt;
&lt;p&gt;Based on the vocabulary categories provided earlier, here are example sentences using some of those words:&lt;/p&gt;
&lt;h3&gt;Employment and Job Interviews&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Resume/CV:&lt;/strong&gt; &quot;I updated my resume to include my most recent job experience.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Qualifications:&lt;/strong&gt; &quot;The job posting listed the qualifications necessary for the position.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interview:&lt;/strong&gt; &quot;I have a job interview scheduled for next week.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Technology (Software and Hardware)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Application (App):&lt;/strong&gt; &quot;The application on my phone helps me manage my daily tasks.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operating System (OS):&lt;/strong&gt; &quot;My computer runs on the latest operating system.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database:&lt;/strong&gt; &quot;The company maintains a large database of customer information.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Daily Life Activities&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Groceries:&lt;/strong&gt; &quot;I need to go to the store to buy groceries for the week.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transportation:&lt;/strong&gt; &quot;Public transportation in this city is very efficient.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dining:&lt;/strong&gt; &quot;We&apos;re dining at a new restaurant downtown tonight.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Idiomatic Expressions&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Break the ice:&lt;/strong&gt; &quot;To break the ice at the party, we played a few rounds of trivia.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Piece of cake:&lt;/strong&gt; &quot;The math problem was a piece of cake for her.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Out of the blue:&lt;/strong&gt; &quot;He called me out of the blue after not speaking for years.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Best regards,
Professor Judy&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.wikihow.com/Study-a-Week-Before-an-Exam&quot;&gt;https://www.wikihow.com/Study-a-Week-Before-an-Exam&lt;/a&gt;
[2] &lt;a href=&quot;https://www.youtube.com/watch?v=7EJOs4AeQGk&quot;&gt;https://www.youtube.com/watch?v=7EJOs4AeQGk&lt;/a&gt;
[3] &lt;a href=&quot;https://shorelight.com/student-stories/21-best-study-tips-for-final-exams/&quot;&gt;https://shorelight.com/student-stories/21-best-study-tips-for-final-exams/&lt;/a&gt;
[4] &lt;a href=&quot;https://www.princetonreview.com/college-advice/back-to-school-study-tips&quot;&gt;https://www.princetonreview.com/college-advice/back-to-school-study-tips&lt;/a&gt;
[5] &lt;a href=&quot;https://www.familyeducation.com/pregnancy/week-12-pregnancy/you-are-11-weeks-2-days-pregnant&quot;&gt;https://www.familyeducation.com/pregnancy/week-12-pregnancy/you-are-11-weeks-2-days-pregnant&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 67 of learning English</title><link>https://blog.ithuo.net/posts/day-67-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-67-of-learning-english/</guid><pubDate>Mon, 05 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dear Derick,&lt;/p&gt;
&lt;p&gt;By week eleven, you should be focusing on refining your conversational skills and expanding your vocabulary to include more specialized topics. Here&apos;s a detailed plan for your eleventh week:&lt;/p&gt;
&lt;h3&gt;Week 11: Specialized Vocabulary and Advanced Conversations&lt;/h3&gt;
&lt;h3&gt;Monday:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Morning:&lt;/strong&gt; Review vocabulary and phrases related to employment and job interviews. Practice with role-playing exercises.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Afternoon:&lt;/strong&gt; Learn about common phrases and expressions used in professional settings.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Tuesday:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Morning:&lt;/strong&gt; Study vocabulary related to technology, focusing on software and hardware terms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Afternoon:&lt;/strong&gt; Engage in a conversation with me about recent developments in software technology.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Wednesday:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Morning:&lt;/strong&gt; Practice listening to English podcasts or watching videos on topics of personal interest to improve comprehension.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Afternoon:&lt;/strong&gt; Write a short essay on a technological topic and review it with me for feedback.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Thursday:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Morning:&lt;/strong&gt; Learn vocabulary related to daily life activities, such as shopping, dining, and transportation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Afternoon:&lt;/strong&gt; Participate in a mock scenario where you have to navigate these daily life situations in English.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Friday:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Morning:&lt;/strong&gt; Focus on understanding and using idiomatic expressions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Afternoon:&lt;/strong&gt; Have a free conversation with me using the idioms learned.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Saturday:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Morning:&lt;/strong&gt; Review all the vocabulary and phrases learned this week.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Afternoon:&lt;/strong&gt; Engage in a comprehensive conversation with me, incorporating this week&apos;s learning.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Sunday:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Day Off:&lt;/strong&gt; Rest and immerse yourself in English media for leisure.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification of Study Results:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Daily Conversations:&lt;/strong&gt; We will have daily conversations about various topics to assess your progress.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Written Assignments:&lt;/strong&gt; You will submit written work, which I will review to ensure proper use of grammar and vocabulary.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Role-Playing Exercises:&lt;/strong&gt; Through role-playing, you will demonstrate your ability to use English in real-life scenarios.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember, consistency is key, and practicing every day will significantly contribute to your progress. Keep up the good work, and let&apos;s continue to push towards your goal of conversational fluency in English.&lt;/p&gt;
&lt;p&gt;Best regards,
Professor Judy&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;On the first day of your eleventh week, you should focus on reviewing vocabulary and phrases related to employment and job interviews, as well as practicing with role-playing exercises. Here&apos;s a breakdown for your study activities:&lt;/p&gt;
&lt;h3&gt;Morning:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Review Vocabulary:&lt;/strong&gt; Start by reviewing vocabulary and phrases that are commonly used in employment contexts and job interviews. This includes terms related to job positions, responsibilities, company culture, and common questions asked during interviews.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Role-Playing Exercises:&lt;/strong&gt; Engage in role-playing exercises where you simulate a job interview scenario. You can prepare a set of questions that are typically asked during interviews and practice answering them in English.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Afternoon:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Learn Professional Phrases:&lt;/strong&gt; Focus on learning phrases and expressions that are commonly used in professional settings. This includes how to introduce yourself professionally, how to talk about your skills and experiences, and how to ask questions about the job or the company.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practice Conversation:&lt;/strong&gt; Have a mock conversation with me or another English speaker, where you use the vocabulary and phrases you&apos;ve learned. This will help you get comfortable speaking about professional topics in English.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification of Study Results:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Role-Playing Feedback:&lt;/strong&gt; After the role-playing exercises, we will discuss your performance, focusing on pronunciation, vocabulary usage, and how confidently you presented yourself.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conversation Review:&lt;/strong&gt; We will review the conversation from the afternoon session, identifying areas of improvement and highlighting your strengths.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This focused approach on your first day back will help you build confidence in discussing professional topics in English, which is essential for achieving conversational fluency. Remember, practice and active participation are key to your success.&lt;/p&gt;
&lt;p&gt;Best regards,
Professor Judy&lt;/p&gt;
&lt;h3&gt;Employment and Job Interviews&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Resume/CV:&lt;/strong&gt; A document detailing your work experience, education, and skills.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Qualifications:&lt;/strong&gt; The abilities, experience, and credentials required for a job.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interview:&lt;/strong&gt; A formal meeting in which someone asks you questions to see if you are suitable for a job or course.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Position:&lt;/strong&gt; The role or job title one holds in a company.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Responsibilities:&lt;/strong&gt; The duties or tasks that are required as part of a job.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Company Culture:&lt;/strong&gt; The shared values, beliefs, and behaviors within a workplace.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Technology (Software and Hardware)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Application (App):&lt;/strong&gt; A program or piece of software designed to fulfill a particular purpose.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operating System (OS):&lt;/strong&gt; The software that supports a computer&apos;s basic functions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database:&lt;/strong&gt; A structured set of data held in a computer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Network:&lt;/strong&gt; A group of interconnected computers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hardware:&lt;/strong&gt; The physical parts of a computer system.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Software:&lt;/strong&gt; The programs and other operating information used by a computer.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Daily Life Activities&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Groceries:&lt;/strong&gt; Items of food sold in a grocery store.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transportation:&lt;/strong&gt; The action of transporting someone or something or the process of being transported.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dining:&lt;/strong&gt; The act of eating out in a restaurant or eating establishment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Budget:&lt;/strong&gt; An estimate of income and expenditure for a set period of time.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Idiomatic Expressions&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Break the ice:&lt;/strong&gt; To initiate social interaction by relieving tension.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Piece of cake:&lt;/strong&gt; Something very easy to do.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hit the books:&lt;/strong&gt; To study hard.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Out of the blue:&lt;/strong&gt; Something happening unexpectedly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can use the strategies mentioned in the search results, such as creating flashcards, engaging in vocabulary games, and using idea webs, to review these words. Additionally, you can use vocabulary review tools like Busuu to focus on words of specific strength, such as weak, medium, or strong words[1]. Engaging in activities like Hotseat and matching games can also make the review process more interactive and enjoyable[3][4].&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.wikihow.com/Study-a-Week-Before-an-Exam&quot;&gt;https://www.wikihow.com/Study-a-Week-Before-an-Exam&lt;/a&gt;
[2] &lt;a href=&quot;https://www.youtube.com/watch?v=7EJOs4AeQGk&quot;&gt;https://www.youtube.com/watch?v=7EJOs4AeQGk&lt;/a&gt;
[3] &lt;a href=&quot;https://www.coursera.org/articles/study-habits&quot;&gt;https://www.coursera.org/articles/study-habits&lt;/a&gt;
[4] &lt;a href=&quot;https://shorelight.com/student-stories/21-best-study-tips-for-final-exams/&quot;&gt;https://shorelight.com/student-stories/21-best-study-tips-for-final-exams/&lt;/a&gt;
[5] &lt;a href=&quot;https://www.princetonreview.com/college-advice/back-to-school-study-tips&quot;&gt;https://www.princetonreview.com/college-advice/back-to-school-study-tips&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 66 of learning English</title><link>https://blog.ithuo.net/posts/day-66-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-66-of-learning-english/</guid><pubDate>Sun, 04 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the seventh day of Week 10 in the study plan, the tasks could include:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Rest and Immersion&lt;/strong&gt;: Take this day to rest from active study and immerse yourself in the English language in a more relaxed way. This could involve watching English-language movies, listening to music, or reading for pleasure in English.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reflect on Learning&lt;/strong&gt;: Reflect on the progress you&apos;ve made over the week. Consider what has been effective and what might need more attention or a different approach.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prepare for Upcoming Week&lt;/strong&gt;: Look ahead to Week 11. Start to think about the topics and materials you will cover. Gather resources and set goals for what you want to achieve.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Casual Practice&lt;/strong&gt;: If you feel inclined, engage in casual English practice by chatting with friends, posting on social media in English, or writing in a journal.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This day should be less structured, allowing for rest and consolidation of the learning from the week, while still engaging with the language in a stress-free way.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.indeed.com/career-advice/finding-a-job/4-10-work-schedule&quot;&gt;https://www.indeed.com/career-advice/finding-a-job/4-10-work-schedule&lt;/a&gt;
[2] &lt;a href=&quot;https://www.youtube.com/watch?v=VpWIueM_LSM&quot;&gt;https://www.youtube.com/watch?v=VpWIueM_LSM&lt;/a&gt;
[3] &lt;a href=&quot;https://www.indeed.com/career-advice/career-development/alternative-work-schedules&quot;&gt;https://www.indeed.com/career-advice/career-development/alternative-work-schedules&lt;/a&gt;
[4] &lt;a href=&quot;https://www.linkedin.com/pulse/make-saturday-working-day-microsoft-project-dale-howard&quot;&gt;https://www.linkedin.com/pulse/make-saturday-working-day-microsoft-project-dale-howard&lt;/a&gt;
[5] &lt;a href=&quot;https://www.ucg.org/bible-study-tools/bible-questions-and-answers/how-can-we-be-sure-that-saturday-is-the-seventh-day&quot;&gt;https://www.ucg.org/bible-study-tools/bible-questions-and-answers/how-can-we-be-sure-that-saturday-is-the-seventh-day&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 65 of learning English</title><link>https://blog.ithuo.net/posts/day-65-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-65-of-learning-english/</guid><pubDate>Sat, 03 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the sixth day of Week 10 in the study plan, considering the focus on language learning and the absence of specific search results related to our English study plan, the tasks could include:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Practical Application&lt;/strong&gt;: Allocate time to apply what you&apos;ve learned in real-world contexts. This could involve:
&lt;ul&gt;
&lt;li&gt;Engaging in conversation practice with a native speaker or language exchange partner.&lt;/li&gt;
&lt;li&gt;Writing a blog post, email, or diary entry using the new vocabulary and grammar structures you&apos;ve learned.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vocabulary Expansion&lt;/strong&gt;: Spend time learning synonyms and antonyms for the week&apos;s vocabulary to deepen your understanding and flexibility in using these words. This can help improve your ability to express yourself more precisely.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Listening Practice&lt;/strong&gt;: Listen to English podcasts, watch movies, or find YouTube videos on topics of interest that include the vocabulary and grammar points you&apos;ve been studying. Try to understand the main ideas and note any new words or expressions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reflection&lt;/strong&gt;: Reflect on your progress over the week. Identify what worked well and what areas need more focus. This can help you adjust your study plan for the following week to address any challenges.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Preparation for Next Week&lt;/strong&gt;: Begin looking ahead to next week&apos;s study plan. Preview the material or topics you plan to cover and start gathering resources or creating a schedule.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These tasks are designed to reinforce the learning from the week, provide opportunities for practical application, and set the stage for continued progress in your language learning journey.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.youtube.com/watch?v=VpWIueM_LSM&quot;&gt;https://www.youtube.com/watch?v=VpWIueM_LSM&lt;/a&gt;
[2] &lt;a href=&quot;https://www.indeed.com/career-advice/finding-a-job/4-10-work-schedule&quot;&gt;https://www.indeed.com/career-advice/finding-a-job/4-10-work-schedule&lt;/a&gt;
[3] &lt;a href=&quot;https://www.linkedin.com/pulse/make-saturday-working-day-microsoft-project-dale-howard&quot;&gt;https://www.linkedin.com/pulse/make-saturday-working-day-microsoft-project-dale-howard&lt;/a&gt;
[4] &lt;a href=&quot;https://www.indeed.com/career-advice/career-development/alternative-work-schedules&quot;&gt;https://www.indeed.com/career-advice/career-development/alternative-work-schedules&lt;/a&gt;
[5] &lt;a href=&quot;https://jarche.com/2007/05/a-six-day-work-week-for-students/&quot;&gt;https://jarche.com/2007/05/a-six-day-work-week-for-students/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 64 of learning English</title><link>https://blog.ithuo.net/posts/day-64-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-64-of-learning-english/</guid><pubDate>Fri, 02 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the fifth day of Week 10 in the study plan, you should complete the following specific tasks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Review Chunk D&lt;/strong&gt;: Spend 30 minutes reviewing the material you prepared on the fourth day. This review should be active, involving self-testing and evaluating your learning to ensure you understand the material well[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review Chunk C&lt;/strong&gt;: Dedicate 15 minutes to review the material you prepared on the third day to reinforce your learning[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review Chunk B and A&lt;/strong&gt;: Spend another 15 minutes reviewing the material from the first and second day to aid in long-term retention[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interactive Activities&lt;/strong&gt;: Engage in interactive activities that reinforce the vocabulary and phonemic awareness you&apos;ve been working on. This could involve playing educational games, having conversations in English, or writing short paragraphs using the vocabulary words you&apos;ve learned[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reflection and Planning&lt;/strong&gt;: Spend the remaining time reflecting on your progress this week. Identify areas of strength and areas needing improvement. Plan adjustments for next week&apos;s study plan based on this reflection.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These tasks are designed to follow a structured approach to learning, breaking down the material into manageable chunks and reviewing them progressively to enhance understanding and retention.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.indeed.com/career-advice/finding-a-job/4-10-work-schedule&quot;&gt;https://www.indeed.com/career-advice/finding-a-job/4-10-work-schedule&lt;/a&gt;
[2] &lt;a href=&quot;https://www.forecast.app/blog/flexible-working-examples&quot;&gt;https://www.forecast.app/blog/flexible-working-examples&lt;/a&gt;
[3] &lt;a href=&quot;https://hubstaff.com/4-10-work-schedule&quot;&gt;https://hubstaff.com/4-10-work-schedule&lt;/a&gt;
[4] &lt;a href=&quot;https://www.hourly.io/post/4-10-work-schedule&quot;&gt;https://www.hourly.io/post/4-10-work-schedule&lt;/a&gt;
[5] &lt;a href=&quot;https://www.twinkl.ie/resource/a-word-a-day-activity-pack-week-10-t-e-1641994005&quot;&gt;https://www.twinkl.ie/resource/a-word-a-day-activity-pack-week-10-t-e-1641994005&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 63 of learning English</title><link>https://blog.ithuo.net/posts/day-63-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-63-of-learning-english/</guid><pubDate>Thu, 01 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the fourth day of Week 10 in the study plan, you should complete the following specific tasks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Prepare Chunk D&lt;/strong&gt;: Dedicate 1 hour to preparing new study material. This could involve learning new vocabulary, grammar points, or language skills[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review Chunk C&lt;/strong&gt;: Spend 30 minutes reviewing the material you prepared on the third day. This review should be active, involving self-testing and evaluating your learning to ensure you understand the material well[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review Chunk B&lt;/strong&gt;: Dedicate 15 minutes to review the material you prepared on the second day to reinforce your learning[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review Chunk A&lt;/strong&gt;: Spend another 15 minutes reviewing the material from the first day to aid in long-term retention[5].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These tasks are designed to follow a structured approach to learning, breaking down the material into manageable chunks and reviewing them progressively to enhance understanding and retention.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.intelligent.com/create-a-study-plan/&quot;&gt;https://www.intelligent.com/create-a-study-plan/&lt;/a&gt;
[2] &lt;a href=&quot;https://blog.prepscholar.com/sat-study-plan&quot;&gt;https://blog.prepscholar.com/sat-study-plan&lt;/a&gt;
[3] &lt;a href=&quot;https://www.linkedin.com/pulse/average-googler-four-weeks-study-plan-milad-naseri&quot;&gt;https://www.linkedin.com/pulse/average-googler-four-weeks-study-plan-milad-naseri&lt;/a&gt;
[4] &lt;a href=&quot;https://www.vu.edu.au/about-vu/news-events/study-space/how-to-make-an-effective-study-plan&quot;&gt;https://www.vu.edu.au/about-vu/news-events/study-space/how-to-make-an-effective-study-plan&lt;/a&gt;
[5] &lt;a href=&quot;https://lsc.cornell.edu/how-to-study/studying-for-and-taking-exams/the-five-day-study-plan/&quot;&gt;https://lsc.cornell.edu/how-to-study/studying-for-and-taking-exams/the-five-day-study-plan/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 62 of learning English</title><link>https://blog.ithuo.net/posts/day-62-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-62-of-learning-english/</guid><pubDate>Wed, 31 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the third day of Week 10, you should focus on the following tasks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Phonemic Awareness&lt;/strong&gt;: Continue practicing the sounds of the letters Hh (/h/) and start working on the sounds of the letter Ww (/w/). Engage in phonics exercises to reinforce these sounds[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;High-Frequency Words&lt;/strong&gt;: Keep practicing the high-frequency words you&apos;ve been focusing on, such as &quot;as,&quot; &quot;has,&quot; &quot;want&quot;[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Comprehension Skills&lt;/strong&gt;: Further develop your comprehension skills by identifying story details, focusing on the setting of the stories you read[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reading&lt;/strong&gt;: Read additional texts that include the new vocabulary words, paying special attention to understanding the context in which they are used[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interactive Activities&lt;/strong&gt;: Play educational games that reinforce the vocabulary and phonemic awareness you&apos;ve been working on. You can continue with &quot;Old Maid&quot; or similar games that use the vocabulary cards[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vocabulary Practice&lt;/strong&gt;: Review the flashcards you created and practice using the new vocabulary words in sentences or short paragraphs[5].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember to review the material from the previous days to reinforce your learning and ensure retention.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.everand.com/book/238024152/Telling-Time-with-the-Judy-Clock-Grade-1&quot;&gt;https://www.everand.com/book/238024152/Telling-Time-with-the-Judy-Clock-Grade-1&lt;/a&gt;
[2] &lt;a href=&quot;https://www.edutopia.org/blog/week-one-selling-value-literacy-judy-jester?qt-discussion_replies=1&quot;&gt;https://www.edutopia.org/blog/week-one-selling-value-literacy-judy-jester?qt-discussion_replies=1&lt;/a&gt;
[3] &lt;a href=&quot;https://www.twinkl.ie/resource/a-word-a-day-activity-pack-week-10-t-e-1641994005&quot;&gt;https://www.twinkl.ie/resource/a-word-a-day-activity-pack-week-10-t-e-1641994005&lt;/a&gt;
[4] &lt;a href=&quot;https://www.reddit.com/r/yandere_simulator/comments/qrm4cl/can_somebody_give_me_a_step_by_step_guide_for/?rdt=36750&quot;&gt;https://www.reddit.com/r/yandere_simulator/comments/qrm4cl/can_somebody_give_me_a_step_by_step_guide_for/?rdt=36750&lt;/a&gt;
[5] &lt;a href=&quot;http://www.navydep.com/forums/showthread.php?t=433&quot;&gt;http://www.navydep.com/forums/showthread.php?t=433&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 61 of learning English</title><link>https://blog.ithuo.net/posts/day-61-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-61-of-learning-english/</guid><pubDate>Tue, 30 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the second day of Week 10, you should complete the following tasks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Phonemic Awareness&lt;/strong&gt;: Continue working on the sounds of the letters Hh (/h/). Practice identifying these sounds at the beginning and ending of words[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;High-Frequency Words&lt;/strong&gt;: Continue practicing high-frequency words such as &quot;as,&quot; &quot;has,&quot; &quot;want&quot;[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Comprehension Skills&lt;/strong&gt;: Continue working on comprehension skills like cause and effect. Practice identifying story details, specifically characters[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reading&lt;/strong&gt;: Read texts that include the new vocabulary words and focus on comprehension skills[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interactive Activities&lt;/strong&gt;: Continue playing the game &quot;Old Maid&quot; using vocabulary cards from weeks 1-9 to reinforce previous learning[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vocabulary Practice&lt;/strong&gt;: Use the flashcards you created on Day 1 to practice the new vocabulary words[5].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember to review and practice consistently throughout the day.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.everand.com/book/238024152/Telling-Time-with-the-Judy-Clock-Grade-1&quot;&gt;https://www.everand.com/book/238024152/Telling-Time-with-the-Judy-Clock-Grade-1&lt;/a&gt;
[2] &lt;a href=&quot;https://www.edutopia.org/blog/week-one-selling-value-literacy-judy-jester?qt-discussion_replies=1&quot;&gt;https://www.edutopia.org/blog/week-one-selling-value-literacy-judy-jester?qt-discussion_replies=1&lt;/a&gt;
[3] &lt;a href=&quot;https://www.twinkl.ie/resource/a-word-a-day-activity-pack-week-10-t-e-1641994005&quot;&gt;https://www.twinkl.ie/resource/a-word-a-day-activity-pack-week-10-t-e-1641994005&lt;/a&gt;
[4] &lt;a href=&quot;https://teach.starfall.com/materials/curriculum/teachers-lounge/week10.pdf&quot;&gt;https://teach.starfall.com/materials/curriculum/teachers-lounge/week10.pdf&lt;/a&gt;
[5] &lt;a href=&quot;https://www.vocabulary.com/lists/333313&quot;&gt;https://www.vocabulary.com/lists/333313&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 60 of learning English</title><link>https://blog.ithuo.net/posts/day-60-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-60-of-learning-english/</guid><pubDate>Mon, 29 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Week 10 Learning Tasks&lt;/h2&gt;
&lt;h3&gt;Vocabulary and Language Structure&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vocabulary Development&lt;/strong&gt;: Focus on learning and using new vocabulary words such as &quot;grain,&quot; &quot;mountain,&quot; &quot;plain,&quot; &quot;everglades,&quot; &quot;beach,&quot; &quot;sea,&quot; &quot;evaporation,&quot; &quot;condensation,&quot; and &quot;precipitation.&quot; Create flashcards for these words and practice them daily.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phonemic Awareness&lt;/strong&gt;: Work on the sounds of the letters Hh (/h/) and Ww (/w/). Practice identifying these sounds at the beginning and ending of words.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;High-Frequency Words&lt;/strong&gt;: Continue to practice high-frequency words such as &quot;as,&quot; &quot;has,&quot; &quot;want,&quot; &quot;a,&quot; &quot;and,&quot; &quot;come,&quot; &quot;go,&quot; &quot;I,&quot; &quot;in,&quot; &quot;it,&quot; &quot;me,&quot; &quot;said,&quot; &quot;see,&quot; &quot;the,&quot; &quot;to,&quot; &quot;we,&quot; &quot;with.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Reading and Comprehension&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reading&lt;/strong&gt;: Read texts that include the new vocabulary words and focus on comprehension skills like cause and effect, story details (characters and setting), and making inferences.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Comprehension Strategies&lt;/strong&gt;: Practice predicting and verifying information in texts. Work on visualizing to enhance understanding.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Speaking and Listening&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Listening&lt;/strong&gt;: Engage in listening exercises that include the new vocabulary and high-frequency words.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Speaking&lt;/strong&gt;: Have daily conversations using the new vocabulary. Discuss topics related to nature and the environment to apply the vocabulary in context.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Writing and Grammar&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Writing&lt;/strong&gt;: Write short paragraphs or sentences using the new vocabulary words. Focus on creating clear descriptions of natural features like mountains, plains, and beaches.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grammar&lt;/strong&gt;: Practice constructing sentences that demonstrate cause and effect, and work on using opposites correctly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Activities&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Interactive Activities&lt;/strong&gt;: Play educational games like &quot;Old Maid&quot; using vocabulary cards from weeks 1-9 to reinforce previous learning.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rhyming and Phonics&lt;/strong&gt;: Engage in rhyming activities and phonics exercises focusing on the sounds of Hh and Ww.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification of Study Results&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Flashcard Review&lt;/strong&gt;: Test your recall of the new vocabulary words with flashcards.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reading Comprehension&lt;/strong&gt;: Answer questions about the texts you read to demonstrate understanding.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Speaking Practice&lt;/strong&gt;: Engage in structured conversations with me about software technology or daily life, using the new vocabulary and grammar structures.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Writing Samples&lt;/strong&gt;: Submit writing samples that will be reviewed for correct use of vocabulary and grammar.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On the first day of Week 10, you should complete the following tasks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Vocabulary Development&lt;/strong&gt;: Generate and prepare vocabulary word cards for the words &quot;grain,&quot; &quot;mountain,&quot; &quot;plain,&quot; &quot;everglades,&quot; &quot;beach,&quot; &quot;sea,&quot; &quot;evaporation,&quot; &quot;condensation,&quot; and &quot;precipitation.&quot; Start learning these words and their meanings[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phonemic Awareness&lt;/strong&gt;: Begin working on the sounds of the letters Hh (/h/). You can use an &quot;ABC Rhyme&quot; practice page for this[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;High-Frequency Words&lt;/strong&gt;: Start practicing high-frequency words such as &quot;as,&quot; &quot;has,&quot; &quot;want&quot;[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Comprehension Skills&lt;/strong&gt;: Start working on comprehension skills like cause and effect, and identifying genres (poetry). Also, start practicing identifying opposites[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interactive Activities&lt;/strong&gt;: Familiarize yourself with the game &quot;Old Maid&quot; and play it using vocabulary cards from weeks 1-9 to reinforce previous learning[4].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember to review and practice consistently throughout the day.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.everand.com/book/238024152/Telling-Time-with-the-Judy-Clock-Grade-1&quot;&gt;https://www.everand.com/book/238024152/Telling-Time-with-the-Judy-Clock-Grade-1&lt;/a&gt;
[2] &lt;a href=&quot;https://www.edutopia.org/blog/week-one-selling-value-literacy-judy-jester?qt-discussion_replies=1&quot;&gt;https://www.edutopia.org/blog/week-one-selling-value-literacy-judy-jester?qt-discussion_replies=1&lt;/a&gt;
[3] &lt;a href=&quot;https://www.twinkl.ie/resource/a-word-a-day-activity-pack-week-10-t-e-1641994005&quot;&gt;https://www.twinkl.ie/resource/a-word-a-day-activity-pack-week-10-t-e-1641994005&lt;/a&gt;
[4] &lt;a href=&quot;https://teach.starfall.com/materials/curriculum/teachers-lounge/week10.pdf&quot;&gt;https://teach.starfall.com/materials/curriculum/teachers-lounge/week10.pdf&lt;/a&gt;
[5] &lt;a href=&quot;https://www.vocabulary.com/lists/333313&quot;&gt;https://www.vocabulary.com/lists/333313&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 59 of learning English</title><link>https://blog.ithuo.net/posts/day-59-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-59-of-learning-english/</guid><pubDate>Sun, 28 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dear Derick,&lt;/p&gt;
&lt;p&gt;On the seventh day of the ninth week, we will focus on reviewing the material covered during the week and practicing conversational English through a discussion with me. Here&apos;s your plan for the day:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Morning Session (1 hour):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the vocabulary, grammar structures, and concepts you&apos;ve learned throughout the week. This includes the advanced vocabulary from Day 1, the passive voice from Day 2, listening comprehension from Day 3, speaking and role-play from Day 4, reading comprehension from Day 5, and the differences between formal and informal language from Day 6.&lt;/li&gt;
&lt;li&gt;Prepare questions and topics for our conversation practice. You can include topics related to software technology, daily life, and work, as well as any other areas of interest.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Evening Session (1 hour):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Engage in a conversation with me about software technology, using the new vocabulary and grammar structures you&apos;ve learned. We can also discuss topics from your daily life and work to practice conversational English in a variety of contexts.&lt;/li&gt;
&lt;li&gt;I will provide feedback on your use of vocabulary, grammar, and pronunciation during our conversation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Verification of Study Results:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I will assess your conversational skills and provide immediate feedback during our discussion. This will help you understand your progress and areas that may need more attention.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This day is important for consolidating your learning and gaining confidence in using English in real-life conversations. Remember, practice makes perfect, and the more you use the language, the more fluent you will become. Don&apos;t hesitate to reach out if you have any questions.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.youtube.com/watch?v=6IANEgOBXi0&quot;&gt;https://www.youtube.com/watch?v=6IANEgOBXi0&lt;/a&gt;
[2] &lt;a href=&quot;https://www.teacherspayteachers.com/Browse/Search:week%209%20vocabulary&quot;&gt;https://www.teacherspayteachers.com/Browse/Search:week 9 vocabulary&lt;/a&gt;
[3] &lt;a href=&quot;https://zapier.com/blog/learning-new-skills/&quot;&gt;https://zapier.com/blog/learning-new-skills/&lt;/a&gt;
[4] &lt;a href=&quot;https://www.edutopia.org/article/first-week-of-high-school-activities/&quot;&gt;https://www.edutopia.org/article/first-week-of-high-school-activities/&lt;/a&gt;
[5] &lt;a href=&quot;https://abetterwaytoteach.com/blogs/news/high-school-english-teachers-i-planned-your-frist-week-back-to-school&quot;&gt;https://abetterwaytoteach.com/blogs/news/high-school-english-teachers-i-planned-your-frist-week-back-to-school&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>周报(1.22-1.28)</title><link>https://blog.ithuo.net/posts/week-1-22-28/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/week-1-22-28/</guid><pubDate>Sun, 28 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;英语学习&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/bac4d7f1630f5a1a9e61a15efcd87bbe.jpeg&quot; alt=&quot;Untitled.jpeg&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;本周读书&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/ead09b455b682a2137e9660d40f2b23e.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;今日开源库：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Google Indexing Script&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://t.co/mfAipBayir&quot;&gt;https://github.com/goenning/google-indexing-script…&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;可以让你的页面快速的被 Google 搜索收录，No tricks, no hacks，48 小时之内有效。&lt;/p&gt;
&lt;p&gt;并且附有一篇很好的文章讲解原理：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://t.co/Uxdy4mdHez&quot;&gt;https://seogets.com/blog/google-indexing-script…&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;作者发现现在（2022-2023） Google 收录的策略有两个：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;they have backlinks pointing to them， 这些页面有 backlinks&lt;/li&gt;
&lt;li&gt;the site owner ask for the page to be indexed via Google Search Console; 网站所有者手动在 Google Search Console 请求被收录&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这个脚本就是利于第二个策略调用 API 批量发送，特别注意的是被收录 不等于 页面的 Rank，还是要不断努力去提升页面的 Rank。&lt;/p&gt;
&lt;p&gt;还有就是&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Google Search Console&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;很好用，能标出你的页面哪些被收录，哪些还没有，遇到了什么问题，你可以按照它的要求进行修改。&lt;/p&gt;
&lt;p&gt;非常棒的一款无损视频/音频编辑的瑞士军刀， LosslessCut 是一款跨平台 FFmpeg GUI，主要功能是对视频和音频文件进行无损修剪和剪切，对视频、音频、字幕和其他相关媒体文件进行极其快速和无损的操作。GitHub 内有免费的下载地址&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://t.co/weK4RD58AF&quot;&gt;https://github.com/mifi/lossless-cut?tab=readme-ov-file&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;前几天刷到了好几个用Pixverse做的好视频，刚好他们最近上线了网页版本和新模型就想顺便测试一下和 Runway 以及 Pika 的质量相比怎么样。&lt;/p&gt;
&lt;p&gt;先说结论：&lt;/p&gt;
&lt;p&gt;如果不考虑其他功能和交互我这次测试的结果&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pixverse和 Pika 的质量接近分别是 74.5 分和 73.5 分。Runway 效果居然最差只有 64.5 分。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Pixverse的模型&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;是这三者最为平衡的，可以有比较强的运动幅度，同时可以维持较好的一致性，模型可以比较好的对提示词进行响应&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;，尤其是 2.5D 那个镜头非常的惊艳，但是纯二次元图片的效果也不是很好。&lt;/p&gt;
&lt;p&gt;Pika 在动漫和 2.5D 风格上的优势巨大，但是只有 Pika 每次生成是 3秒钟，所以图像质量打分会比其他两个差，写实风格效果也不是很如意，图像质量以及一致性相对差一些。&lt;/p&gt;
&lt;p&gt;Runway 的模型质量和上面两者差距较大，主要是二次元风格的还原度太差还有 2.5D 风格直接无法维持一致性，写实场景对复杂画面改动较大有时候无法维持画面一致性，但是 Runway 对生成内容的控制还是三者最强的，因为其他两个都没有所以这部分就不计入分数。&lt;/p&gt;
&lt;p&gt;这里使用Pixverse：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://t.co/PjnSeUhYbi&quot;&gt;https://app.pixverse.ai/create/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;说一下测试的内容这次只测试视频模型的质量，所以三者都会使用图生视频来测试，这样可以忽略各自的图像模型的差距。&lt;/p&gt;
&lt;p&gt;另外每个都会使用物品特写、写实风景、写实人像、皮克斯 2.5D 风格、 2D 动画风格，这五种风格，然后每张图片生成的视频会从主题一致性、运动平滑度、运动程度以及成像质量这四个维度进行主观评分，每张图片随机一次，所以评分非常主观不保证复现，就是给大家使用的时候一个参考。&lt;/p&gt;
&lt;p&gt;下面是具体每个测试的分数，视频是三者生成视频的对比：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;物品特写-橘子落水：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Runway   主题一致性4分、运动平滑度 4分、运动程度 4.5分、成像质量 3.5分 、总分： 16
Pixverse 主题一致性4分、运动平滑度 4分、运动程度 3.5分 、成像质量 4分 、总分：15.5
Pika 主题一致性 3.5分、运动平滑度 4分、运动程度 4分 、成像质量 3.5分、总分：15&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;写实风景-伦敦塔着火：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Runway：主题一致性2分、运动平滑度 4分、运动程度 4分、成像质量 3.5分 、总分： 13.5
Pixverse：主题一致性4分、运动平滑度 4分、运动程度 3.5分 、成像质量 4分 、总分：15.5
Pika：主题一致性 3.5分、运动平滑度 3.5分、运动程度 3.5分 、成像质量 3.5分、总分：14&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;皮克斯 2.5D 风格-拟人狐狸：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Runway：主题一致性2分、运动平滑度 3.5分、运动程度 4分、成像质量 2分 、总分： 11.5
Pixverse：主题一致性4分、运动平滑度 4分、运动程度 4分 、成像质量 4分 、总分：16
Pika：主题一致性 3.5分、运动平滑度 4分、运动程度 3.5分 、成像质量 3.5分、总分：14.5&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;写实人像-水面古装：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Runway：主题一致性4分、运动平滑度 4分、运动程度 2分、成像质量 3.5分 、总分： 13.5
Pixverse：主题一致性4分、运动平滑度 4分、运动程度 4分 、成像质量 4分 、总分：16
Pika：主题一致性 3分、运动平滑度 3.5分、运动程度 4.5分 、成像质量 3分、总分：14&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;动漫场景-植物园女孩：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Runway：主题一致性 1分、运动平滑度 2分、运动程度 4分、成像质量 3分 、总分：10
Pixverse：主题一致性3分、运动平滑度 3分、运动程度 2.5分 、成像质量 3分 、总分：11.5
Pika：主题一致性 4分、运动平滑度 4分、运动程度 4.5分 、成像质量 3.5分、总分：16&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;总分： Runway：64.5、Pixverse：74.5 、Pika：73.5&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/8351a7b596b01919c502e83d6a2cc63b.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 58 of learning English</title><link>https://blog.ithuo.net/posts/day-58-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-58-of-learning-english/</guid><pubDate>Sat, 27 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dear Derick,&lt;/p&gt;
&lt;p&gt;On the sixth day of the ninth week, we will focus on understanding the differences between formal and informal language in English, particularly in the context of technology and software. Here&apos;s your plan for the day:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Morning Session (1 hour):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learn the differences between formal and informal language. Formal language is typically used in professional, academic, or official contexts, while informal language is used in everyday conversation and casual contexts.&lt;/li&gt;
&lt;li&gt;Practice writing an email to a colleague about a software issue using formal language. This should include appropriate greetings, clear and concise language, and a professional tone.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Evening Session (30 minutes):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Write a message to a friend about the same software issue using informal language. This can be more casual and conversational, and it&apos;s okay to use slang or abbreviations that you would normally use in a casual conversation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Verification of Study Results:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Send me the email and message you&apos;ve written. I will review them to ensure you&apos;re using formal and informal language appropriately and provide feedback or corrections if necessary.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Understanding the differences between formal and informal language will help you communicate effectively in different contexts. Remember, practice is key, and don&apos;t hesitate to reach out if you have any questions.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.youtube.com/watch?v=6IANEgOBXi0&quot;&gt;https://www.youtube.com/watch?v=6IANEgOBXi0&lt;/a&gt;
[2] &lt;a href=&quot;https://www.teacherspayteachers.com/Browse/Search:week%209%20vocabulary&quot;&gt;https://www.teacherspayteachers.com/Browse/Search:week 9 vocabulary&lt;/a&gt;
[3] &lt;a href=&quot;https://abetterwaytoteach.com/blogs/news/high-school-english-teachers-i-planned-your-frist-week-back-to-school&quot;&gt;https://abetterwaytoteach.com/blogs/news/high-school-english-teachers-i-planned-your-frist-week-back-to-school&lt;/a&gt;
[4] &lt;a href=&quot;https://www.nytimes.com/2021/08/23/learning/14-ways-to-learn-vocabulary-and-explore-language-with-the-new-york-times.html&quot;&gt;https://www.nytimes.com/2021/08/23/learning/14-ways-to-learn-vocabulary-and-explore-language-with-the-new-york-times.html&lt;/a&gt;
[5] &lt;a href=&quot;https://www.edutopia.org/article/first-week-of-high-school-activities/&quot;&gt;https://www.edutopia.org/article/first-week-of-high-school-activities/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 57 of learning English</title><link>https://blog.ithuo.net/posts/day-57-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-57-of-learning-english/</guid><pubDate>Fri, 26 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dear Derick,&lt;/p&gt;
&lt;p&gt;On the fifth day of the ninth week, we will focus on improving your reading comprehension skills, particularly in the context of technology and software. Here&apos;s your plan for the day:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Morning Session (1 hour):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read an article about recent developments in software technology. You can find these on tech news websites or blogs. Try to choose an article that is at your current language level or slightly above to challenge yourself.&lt;/li&gt;
&lt;li&gt;As you read, highlight any unknown words or phrases. Try to understand them from the context first, then look them up in a dictionary if needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Evening Session (30 minutes):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Write a brief summary of the article in English. This will help reinforce what you&apos;ve learned and practice expressing ideas in your own words.&lt;/li&gt;
&lt;li&gt;Review the new words or phrases you encountered and add them to your vocabulary list.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Verification of Study Results:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Send me the summary you&apos;ve written. I will review it to ensure you&apos;ve understood the main points and provide feedback or corrections if necessary.&lt;/li&gt;
&lt;li&gt;Also, share the new words or phrases you&apos;ve learned. I can help explain any that you&apos;re having trouble with.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Reading comprehension is crucial for understanding written English, and practicing with real-world articles will help you become more comfortable with technical language. Remember, regular practice is key, and don&apos;t hesitate to reach out if you have any questions.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.teacherspayteachers.com/Browse/Search:week%209%20vocabulary&quot;&gt;https://www.teacherspayteachers.com/Browse/Search:week 9 vocabulary&lt;/a&gt;
[2] &lt;a href=&quot;https://www.edutopia.org/article/first-week-of-high-school-activities/&quot;&gt;https://www.edutopia.org/article/first-week-of-high-school-activities/&lt;/a&gt;
[3] &lt;a href=&quot;https://abetterwaytoteach.com/blogs/news/high-school-english-teachers-i-planned-your-frist-week-back-to-school&quot;&gt;https://abetterwaytoteach.com/blogs/news/high-school-english-teachers-i-planned-your-frist-week-back-to-school&lt;/a&gt;
[4] &lt;a href=&quot;https://www.nytimes.com/2021/08/23/learning/14-ways-to-learn-vocabulary-and-explore-language-with-the-new-york-times.html&quot;&gt;https://www.nytimes.com/2021/08/23/learning/14-ways-to-learn-vocabulary-and-explore-language-with-the-new-york-times.html&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 56 of learning English</title><link>https://blog.ithuo.net/posts/day-56-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-56-of-learning-english/</guid><pubDate>Thu, 25 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dear Derick,&lt;/p&gt;
&lt;p&gt;On the fourth day of the ninth week, we will focus on improving your speaking skills through role-play scenarios. Here&apos;s your plan for the day:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Morning Session (1 hour):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prepare a role-play scenario where you have to explain a software problem and its solution. This could be a real issue you&apos;ve encountered in your work or a hypothetical situation.&lt;/li&gt;
&lt;li&gt;Practice speaking out loud, using the vocabulary and grammar structures you&apos;ve learned so far. Try to use the passive voice where appropriate, as you learned on the second day of this week.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Evening Session (30 minutes):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Record yourself explaining the software problem and solution. This will allow you to listen back and identify areas where you might need improvement.&lt;/li&gt;
&lt;li&gt;Pay attention to your pronunciation, the fluency of your speech, and your use of vocabulary and grammar.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Verification of Study Results:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Send me the recording of your role-play scenario. I will listen to it and provide feedback on your pronunciation, fluency, vocabulary usage, and grammar.&lt;/li&gt;
&lt;li&gt;This feedback will help you identify areas where you&apos;re doing well and where you might need to focus more in your studies.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Role-play is a great way to practice speaking English because it allows you to use the language in a realistic context. Remember, the more you practice, the more comfortable you will become with speaking English. Don&apos;t hesitate to reach out if you have any questions.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.youtube.com/watch?v=6IANEgOBXi0&quot;&gt;https://www.youtube.com/watch?v=6IANEgOBXi0&lt;/a&gt;
[2] &lt;a href=&quot;https://abetterwaytoteach.com/blogs/news/high-school-english-teachers-i-planned-your-frist-week-back-to-school&quot;&gt;https://abetterwaytoteach.com/blogs/news/high-school-english-teachers-i-planned-your-frist-week-back-to-school&lt;/a&gt;
[3] &lt;a href=&quot;https://www.edutopia.org/article/first-week-of-high-school-activities/&quot;&gt;https://www.edutopia.org/article/first-week-of-high-school-activities/&lt;/a&gt;
[4] &lt;a href=&quot;https://www.readingrockets.org/topics/vocabulary/articles/four-practical-principles-enhancing-vocabulary-instruction&quot;&gt;https://www.readingrockets.org/topics/vocabulary/articles/four-practical-principles-enhancing-vocabulary-instruction&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 55 of learning English</title><link>https://blog.ithuo.net/posts/day-55-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-55-of-learning-english/</guid><pubDate>Wed, 24 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dear Derick,&lt;/p&gt;
&lt;p&gt;On the third day of the ninth week, we will focus on improving your listening skills, particularly in the context of technology and software. Here&apos;s your plan for the day:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Morning Session (1 hour):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Listen to podcasts or watch videos related to technology in English. You can find these on platforms like YouTube, Spotify, or dedicated tech websites. Try to choose content that is at your current language level or slightly above to challenge yourself.&lt;/li&gt;
&lt;li&gt;As you listen or watch, focus on understanding the main ideas and identifying any new vocabulary. Don&apos;t worry if you don&apos;t understand everything; the goal is to improve your ability to follow along and pick up the main points.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Evening Session (30 minutes):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Summarize the content of the podcast or video in English. This will help reinforce what you&apos;ve learned and practice expressing ideas in your own words.&lt;/li&gt;
&lt;li&gt;Look up any new words or phrases you encountered and add them to your vocabulary list.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Verification of Study Results:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Send me the summary you&apos;ve written. I will review it to ensure you&apos;ve understood the main points and provide feedback or corrections if necessary.&lt;/li&gt;
&lt;li&gt;Also, share the new words or phrases you&apos;ve learned. I can help explain any that you&apos;re having trouble with.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Listening practice is crucial for developing your understanding of spoken English and getting used to different accents and speaking speeds. Remember, regular practice is key, and don&apos;t hesitate to reach out if you have any questions.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.youtube.com/watch?v=6IANEgOBXi0&quot;&gt;https://www.youtube.com/watch?v=6IANEgOBXi0&lt;/a&gt;
[2] &lt;a href=&quot;https://www.teacherspayteachers.com/Browse/Search:week%209%20vocabulary&quot;&gt;https://www.teacherspayteachers.com/Browse/Search:week 9 vocabulary&lt;/a&gt;
[3] &lt;a href=&quot;https://www.edutopia.org/article/first-week-of-high-school-activities/&quot;&gt;https://www.edutopia.org/article/first-week-of-high-school-activities/&lt;/a&gt;
[4] &lt;a href=&quot;https://abetterwaytoteach.com/blogs/news/high-school-english-teachers-i-planned-your-frist-week-back-to-school&quot;&gt;https://abetterwaytoteach.com/blogs/news/high-school-english-teachers-i-planned-your-frist-week-back-to-school&lt;/a&gt;
[5] &lt;a href=&quot;https://www.greatschools.org/gk/articles/9th-grade-vocabulary-words/&quot;&gt;https://www.greatschools.org/gk/articles/9th-grade-vocabulary-words/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 54 of learning English</title><link>https://blog.ithuo.net/posts/day-54-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-54-of-learning-english/</guid><pubDate>Tue, 23 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dear Derick,&lt;/p&gt;
&lt;p&gt;On the second day of the ninth week, we will focus on understanding and using the passive voice in English. Here&apos;s your plan for the day:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Morning Session (1 hour):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Study the passive voice, which is used when the focus is on the action or the object of the sentence rather than the subject. For example, &quot;The software was updated by the developer&quot; instead of &quot;The developer updated the software.&quot;&lt;/li&gt;
&lt;li&gt;Learn how to form the passive voice with the verb &quot;to be&quot; and the past participle of the main verb.&lt;/li&gt;
&lt;li&gt;Go through examples of passive voice in technology-related sentences.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Evening Session (30 minutes):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Complete exercises that involve converting sentences from active to passive voice and vice versa. This will help you understand how the structure changes and when to use each form.&lt;/li&gt;
&lt;li&gt;Try to create sentences that could be used in your daily work or in discussions about software technology.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Verification of Study Results:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Send me the sentences you&apos;ve converted or created. I will review them to ensure you are using the passive voice correctly and provide feedback or corrections if necessary.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Understanding the passive voice will enhance your ability to read and write about processes and actions in English, which is particularly useful in technical fields. Keep practicing, and don&apos;t hesitate to reach out if you have any questions.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.youtube.com/watch?v=6IANEgOBXi0&quot;&gt;https://www.youtube.com/watch?v=6IANEgOBXi0&lt;/a&gt;
[2] &lt;a href=&quot;https://www.edutopia.org/article/first-week-of-high-school-activities/&quot;&gt;https://www.edutopia.org/article/first-week-of-high-school-activities/&lt;/a&gt;
[3] &lt;a href=&quot;https://abetterwaytoteach.com/blogs/news/high-school-english-teachers-i-planned-your-frist-week-back-to-school&quot;&gt;https://abetterwaytoteach.com/blogs/news/high-school-english-teachers-i-planned-your-frist-week-back-to-school&lt;/a&gt;
[4] &lt;a href=&quot;https://www.greatschools.org/gk/articles/9th-grade-vocabulary-words/&quot;&gt;https://www.greatschools.org/gk/articles/9th-grade-vocabulary-words/&lt;/a&gt;
[5] &lt;a href=&quot;https://www.youtube.com/watch?v=UkOONjClb3g&quot;&gt;https://www.youtube.com/watch?v=UkOONjClb3g&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 53 of learning English</title><link>https://blog.ithuo.net/posts/day-53-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-53-of-learning-english/</guid><pubDate>Mon, 22 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dear Derick,&lt;/p&gt;
&lt;p&gt;On the first day of the ninth week, we will focus on advanced vocabulary building, particularly in the context of technology and software. Here&apos;s the detailed plan:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Morning Session (1 hour):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learn new vocabulary related to technology and software. You can use resources like online dictionaries, language learning apps, or English language textbooks that focus on technical English.&lt;/li&gt;
&lt;li&gt;Use flashcards and spaced repetition software to aid memorization. This method involves reviewing the flashcards at increasing intervals, which helps to move the new words from your short-term memory to your long-term memory.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Evening Session (30 minutes):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Write sentences using the new vocabulary. This will help you understand the context in which these words are used and will reinforce your memory of them. Try to write sentences that are relevant to your work or daily life to make the learning process more meaningful and practical.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Verification of Study Results:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;At the end of the day, send me the sentences you&apos;ve written. I will provide feedback on your usage of the new vocabulary and correct any errors. This will ensure that you&apos;re using the new words correctly and effectively.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember, learning a new language is a gradual process, and it&apos;s important to review and practice regularly. Don&apos;t hesitate to ask if you have any questions or difficulties.&lt;/p&gt;
&lt;p&gt;Here are 25 new words for you to learn:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Abnegation:&lt;/strong&gt; Self-denial&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ambigue:&lt;/strong&gt; Ambiguous&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Athleisure:&lt;/strong&gt; Sportswear&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Briogus:&lt;/strong&gt; Furious&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chillax:&lt;/strong&gt; Relax and chill out&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cringe:&lt;/strong&gt; Feel embarrassment or disgust&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ghost:&lt;/strong&gt; To suddenly cut off all contact with someone&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Facepalm:&lt;/strong&gt; The act of slapping your forehead with your hand in frustration or disbelief&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Binge Watch:&lt;/strong&gt; Watch multiple episodes of a TV show in one sitting&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mansplain:&lt;/strong&gt; When a man explains something to a woman in a condescending manner&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Whatevs:&lt;/strong&gt; Short for &quot;whatever&quot;, used to express indifference or dismissal&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Freegan:&lt;/strong&gt; A person who rejects consumerism, often eating discarded food&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Weak Sauce:&lt;/strong&gt; Something that is of poor quality or unimpressive&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fast Fashion:&lt;/strong&gt; Inexpensive clothing produced rapidly by mass-market retailers in response to the latest trends&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sriracha:&lt;/strong&gt; A type of hot sauce made from a paste of chili peppers, distilled vinegar, garlic, sugar, and salt&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EVOO:&lt;/strong&gt; Short for &quot;extra virgin olive oil&quot;, a type of high-quality oil used in cooking&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Abundance:&lt;/strong&gt; Plenty&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accentuate:&lt;/strong&gt; Emphasize&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acquiesce:&lt;/strong&gt; Consent&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Align:&lt;/strong&gt; Position&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Emmersion:&lt;/strong&gt; The process of becoming completely involved in something&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Comprehensive:&lt;/strong&gt; Complete; including all or nearly all elements or aspects of something&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Immersive:&lt;/strong&gt; Providing, involving, or characterized by deep absorption or immersion in something&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trusted:&lt;/strong&gt; Regarded as reliable or truthful&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Educator:&lt;/strong&gt; A person who provides instruction or education[1][2][3][5].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://abetterwaytoteach.com/blogs/news/high-school-english-teachers-i-planned-your-frist-week-back-to-school&quot;&gt;https://abetterwaytoteach.com/blogs/news/high-school-english-teachers-i-planned-your-frist-week-back-to-school&lt;/a&gt;
[2] &lt;a href=&quot;https://www.edutopia.org/article/first-week-of-high-school-activities/&quot;&gt;https://www.edutopia.org/article/first-week-of-high-school-activities/&lt;/a&gt;
[3] &lt;a href=&quot;https://raisingchildren.net.au/babies/development/language-development/language-3-12-months&quot;&gt;https://raisingchildren.net.au/babies/development/language-development/language-3-12-months&lt;/a&gt;
[4] &lt;a href=&quot;https://www.washington.edu/news/2013/01/02/while-in-womb-babies-begin-learning-language-from-their-mothers/&quot;&gt;https://www.washington.edu/news/2013/01/02/while-in-womb-babies-begin-learning-language-from-their-mothers/&lt;/a&gt;
[5] &lt;a href=&quot;https://www.youtube.com/watch?v=6IANEgOBXi0&quot;&gt;https://www.youtube.com/watch?v=6IANEgOBXi0&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 52 of learning English</title><link>https://blog.ithuo.net/posts/day-52-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-52-of-learning-english/</guid><pubDate>Sun, 21 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the seventh day of Week 8, you should focus on review and self-assessment. Here&apos;s a detailed plan:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Review&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the vocabulary, grammar, listening, speaking, reading, and writing skills you&apos;ve practiced over the past six days. This includes going over your notes, recordings, and written exercises.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Self-Assessment&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Test your understanding of the new vocabulary by using each word in a sentence. Check if you&apos;ve used the words correctly in terms of meaning and context.&lt;/li&gt;
&lt;li&gt;Listen to the recordings of your speaking exercises. Assess your pronunciation, fluency, and use of vocabulary and grammar.&lt;/li&gt;
&lt;li&gt;Read your written exercises and check for correct usage of vocabulary and grammar. Also, assess your ability to express your thoughts clearly and coherently in English.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Practice Conversations&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If possible, arrange a conversation practice with a native English speaker. This could be a language exchange partner, a tutor, or a friend. Try to use the new vocabulary and grammar structures you&apos;ve learned this week.&lt;/li&gt;
&lt;li&gt;If a conversation partner is not available, simulate a conversation by responding to prompts or questions. Record your responses and listen to them for self-evaluation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Relaxation&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Take some time to relax and let your brain process the information you&apos;ve learned this week. This could involve doing something enjoyable that doesn&apos;t involve studying, such as watching a movie, going for a walk, or spending time with friends.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Planning for Next Week&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Look ahead to the next week of your study plan. Familiarize yourself with the topics and skills you&apos;ll be focusing on, and prepare any necessary materials.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By engaging in these activities, you will consolidate your learning from the past week, assess your progress, and prepare yourself for the next week of study[1][2][3].&lt;/p&gt;
&lt;p&gt;To effectively practice using new words in sentences on the seventh day of Week 8, consider the following strategies:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Spaced Repetition&lt;/strong&gt;: Use the new words immediately, then try to recall and use them in sentences after an hour, before bed, the next day, and a few days later to reinforce retention[1].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Record Your Speech&lt;/strong&gt;: Talk about a topic and record your speech. Listen to the recording to see if you used any of the new words and identify opportunities to replace familiar words with new vocabulary. Then, make a new recording to see if there&apos;s improvement[1].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Play Word Games&lt;/strong&gt;: Engage in vocabulary games like bingo, Pictionary, or charades using the new words. This helps reinforce the words in a fun and memorable way[2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Challenge Yourself&lt;/strong&gt;: Try to use the new vocabulary in different contexts, such as at home or during other activities. Keep a vocabulary notebook to jot down when you use the words[2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Write Vocabulary Short Stories&lt;/strong&gt;: Create short stories using the new words to show mastery and help remember them in context[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Word of the Week&lt;/strong&gt;: Focus on a few words each week and explore them in depth. Use them in different sentences each day to deepen your understanding[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Million Dollar Word Club&lt;/strong&gt;: Challenge yourself to use a new vocabulary word in class or daily conversation. Recognize each successful use as a personal achievement[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Post-it Stations&lt;/strong&gt;: Place vocabulary words around your study area and write original sentences using those words on sticky notes[4].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By integrating these strategies into your study routine, you will be able to practice and remember the new words more effectively, which will help you use them confidently in conversation.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.spokaneschools.org/cms/lib/WA50000187/Centricity/Domain/2465/Hays_week7_7th_ELA_Instructions.pdf&quot;&gt;https://www.spokaneschools.org/cms/lib/WA50000187/Centricity/Domain/2465/Hays_week7_7th_ELA_Instructions.pdf&lt;/a&gt;
[2] &lt;a href=&quot;https://ou.edu/content/dam/UniversityCollege/Documents/SLC/5-Day-Study-Plan-8-Week-Courses.pdf&quot;&gt;https://ou.edu/content/dam/UniversityCollege/Documents/SLC/5-Day-Study-Plan-8-Week-Courses.pdf&lt;/a&gt;
[3] &lt;a href=&quot;https://www.teachstarter.com/us/blog/how-to-write-lesson-plan-printable-lesson-plan-template/&quot;&gt;https://www.teachstarter.com/us/blog/how-to-write-lesson-plan-printable-lesson-plan-template/&lt;/a&gt;
[4] &lt;a href=&quot;https://www.apu.apus.edu/docs/shared/course-syllabus/PSYC432.pdf&quot;&gt;https://www.apu.apus.edu/docs/shared/course-syllabus/PSYC432.pdf&lt;/a&gt;
[5] &lt;a href=&quot;https://www.patenteducationseries.com/study-plans/8-week-study-plan.pdf&quot;&gt;https://www.patenteducationseries.com/study-plans/8-week-study-plan.pdf&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>周报(1.15-1.21)</title><link>https://blog.ithuo.net/posts/weekly-report-1-15-1-21/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/weekly-report-1-15-1-21/</guid><pubDate>Sun, 21 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;周二醒来看到地上厚厚的雪，这应该是今年最后一场雪了&lt;/p&gt;
&lt;p&gt;不必愧疚的几件事：
一、把事情搞砸。
二、不符合别人的期待。
三、拒绝别人的要求。
四、离开或终结不合适的关系。
五、存在本身。（生而为人，不必愧疚。这是最根本的一条）&lt;/p&gt;
&lt;p&gt;「每种情绪背后的需求」&lt;/p&gt;
&lt;p&gt;1、情绪没有好坏之分，存在即合理。情绪是人类不断进化的产物，每一种情绪都是在保护我们，都有其存在的道理。&lt;/p&gt;
&lt;p&gt;好的情绪管理是善于看到情绪背后的需求，而不是只是看到情绪本身。&lt;/p&gt;
&lt;p&gt;2、人的心理过程往往是非线性的，但在孕育成强烈体验之前我们常常无法察觉其间因果。&lt;/p&gt;
&lt;p&gt;3、情绪背后的需求也像是一个中转站，作为过渡空间缓冲加载，避免直达激荡的状况无法控制。而探索情绪背后的需求正好是将情感和意图共通。&lt;/p&gt;
&lt;h3&gt;英语学习&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/e6bbb344c6624a8b144c1770e65b77a5.jpeg&quot; alt=&quot;Untitled.jpeg&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;读书&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/0af9b1ba20cc13116f510c5d3951f0f3.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;本周读完的书是杰森·冯的《癌症密码》&lt;/li&gt;
&lt;li&gt;从本书中了解到，癌症不是外敌入侵，而是一场内部叛乱。所有的癌症都起源于人体的正常细胞。人体内几乎每种类型的细胞都有潜在癌变的可能。每种类型的细胞都会导致不同类型的癌症。
环境在癌症的发展中起着关键作用，而生活方式所起的作用也远超人们的想象。
作者还特别提到饮食、肥胖也是造成细胞病变的危险因子, 尤其是高胰岛素血症疾病, 包括肥胖症和2型糖尿病等。
注意饮食的均衡、坚持运动、充足的睡眠、保持身心愉悦，并且远离有害身体的化学物质、辐射、病毒等，维持自身免疫系统健康运作，这些都有助于预防或减缓癌症的发生。
如果想知道癌症是怎样产生的，为什么有那么多种癌症，为什么越来越多的人死于癌症，怎样对抗癌症，有没有可能战而胜之？作者在这本书里给出了答案。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;AI&lt;/h3&gt;
&lt;p&gt;微软推出针对学生的AI阅读教练工具：Reading Coach
你可以选择角色和设定，创建独特的AI生成故事。通过AI驱动的故事和个性化练习吸引学生阅读并提高阅读流畅度。
当你阅读时，语音转文本AI分析阅读流利性，检测学习者挑战的词汇，并记录阅读的准确性、速度和时间。
用来改进你的阅读和语音语法问题。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;以下是其主要功能：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1、个性化阅读练习：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;提供个性化、有趣、一致且独立的阅读流利性练习。
**2、**AI生成故事：学习者可以选择角色和设定，创建独特的AI生成故事。故事内容经过内容质量、安全性和适龄性的审核，符合Microsoft的负责任AI指南。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3、沉浸式阅读器：对&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;有阅读障碍（如诵读困难）的学习者，内置的沉浸式阅读器提供支持。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4、即时反馈：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;阅读时，语音转文本AI分析阅读流利性，检测学习者挑战的词汇，并记录阅读的准确性、速度和时间。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5、互动性阅读：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;学习者在故事章节中做出选择，通过故事导航自己的阅读旅程。上一章节中挑战的词汇会自动纳入下一章节，实现即时适应性练习。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6、流利性教练：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在每个故事章节后，提供针对挑战词汇的流利性指导。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;7、激励机制：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;通过努力为中心的徽章，解锁新角色和设定，以保持学习者的阅读动力。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://t.co/k4kv6M5H4N&quot;&gt;https://coach.microsoft.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/d84d39cd2caa1c5368ceda5ebda00019.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;MSCS&lt;/h3&gt;
&lt;p&gt;提交了三份作业，只有一份通过，教授没有对未通过的作业提供反馈，后续的作业也没有提交，本周进度有点缓慢。再学习的过程中发现美国学校和中国学校的不同，会不断的去拓展知识边界，而且很多作业没有标准答案，只要有足够的理由去证明，那你可能就是对的&lt;/p&gt;
&lt;p&gt;最近学的C++明显感觉没有那么抗拒了，可能是因为它可以去面向对象，能结构化处理，应该静下心来，不用那么焦躁，总是想做的事情很多，但是人的精力是有限的&lt;/p&gt;
&lt;h3&gt;软件分享&lt;/h3&gt;
&lt;p&gt;Sumatra PDF，是我在 Windows 端必装并推荐的开源免费 PDF 阅读器，真正的体积小，启动速度快。&lt;a href=&quot;https://t.co/1VNYwxRL7L&quot;&gt;https://sumatrapdfreader.org&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://free-for.dev/#/&quot;&gt;Free for Developers (free-for.dev)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/VoidAsuka&quot;&gt;@VoidAsuka&lt;/a&gt; 打算做独立产品，以下是规划的技术栈，请大家提供建议&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/d1f143383c65371ebe08fdd64a92d8c5.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/lilingxi01&quot;&gt;@lilingxi01&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;鉴权的话 Clerk 强推，Supabase 还行但是对前端库的依赖有点高，会增加产品后期的复杂性。如果是部署类服务，前端推荐 Next.js 或者 Svelte，后端推荐 TRPC 或者 Bun，部署侧搭配 Vercel 或 Digital Ocean 的 App Platform 都有现成的 CI/CD 解决方案非常省事。移动端应用推荐原生语言，如果要考虑省成本就 React Native。电脑端应用推荐 Tauri。Supabase 对 Postgres 的 RLS 依赖挺高的所以我一般还是普通 Postgres 配合 Prisma 使用然后用 Clerk 做鉴权。Clerk 提供一万的免费月活，目前的唯一问题是 Swift 端跟进得不太好，但是官方有在加紧做了，而且最近招了一些很大牛的设计，看着很养眼，所以总体挺不错的。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@xqliu
🌐 2024 JavaScript / Next.js Programmer’s Complete Free Architecture for solo entrepreneur:

🔧 Front-end and Back-end Deployment: Vercel @vercel
💾 Database: Supabase @supabase
🗂️ File/Object Storage: Supabase
👥 User Management/Authentication: Supabase
📊 Website Analytics: Beamanalytics @BeamAnalyticsIO
📣 Promotion: YouTube, Twitter, Reddit, Hacknews, HackNews etc. 
💻 Code Storage: GitHub
📬 Mailing List: Lemonsqueezy
💳 Payment/E-commerce: Lemonsqueezy @lmsqueezy
📌 Event Tracking: Logsnag @LogSnag
📈 Status Page: BetterStack @BetterStackHQ
🔍 Log Tracking: BetterStack
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;面向开发者的技术栈推荐&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://devbase.fyi/&quot;&gt;DevBase - Product Gallery for Developers&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;云原生环境，开发，部署，运维，监控一体化平台，由GitHub账户切入，&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://zeabur.com/&quot;&gt;https://zeabur.com/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 51 of learning English</title><link>https://blog.ithuo.net/posts/day-51-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-51-of-learning-english/</guid><pubDate>Sat, 20 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the sixth day of Week 8, you should focus on reading comprehension and writing skills. Here&apos;s a detailed plan:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reading Comprehension&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Choose two English-language articles or blog posts related to software technology and daily life. Read each one carefully, trying to understand as much as possible.&lt;/li&gt;
&lt;li&gt;Highlight or note down any new vocabulary or phrases you encounter and look up their meanings.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Writing Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Write a summary of each article or blog post in your own words. This will help you understand the main points and structure of the text.&lt;/li&gt;
&lt;li&gt;Write a response or opinion about the topic of each article or blog post. This will help you practice expressing your thoughts in English.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Vocabulary Review&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the vocabulary you&apos;ve learned over the past five days. Try to identify and understand these words in the context of what you&apos;ve read.&lt;/li&gt;
&lt;li&gt;Use the new vocabulary in your writing exercises to reinforce your understanding and memory.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Grammar Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Identify and practice using any new grammar structures you&apos;ve encountered in your reading. This could include different verb tenses, sentence structures, or punctuation rules.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Verification&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;At the end of the day, review your writing exercises. Check for correct usage of vocabulary and grammar, and make any necessary corrections.&lt;/li&gt;
&lt;li&gt;If possible, have a native English speaker or tutor review your writing and provide feedback.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By engaging in these activities, you will enhance your reading comprehension and writing skills, expand your vocabulary, and improve your grammar, all of which are essential for achieving conversational fluency in English[1][4].&lt;/p&gt;
&lt;p&gt;On the sixth day of Week 8, to practice using new words in sentences effectively, you can employ the following strategies:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Spaced Repetition&lt;/strong&gt;: Use the new words immediately, then try to recall and use them in sentences after an hour, before bed, the next day, and a few days later to reinforce retention[1].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Record Your Speech&lt;/strong&gt;: Talk about a topic and record your speech. Listen to the recording to see if you used any of the new words and identify opportunities to replace familiar words with new vocabulary. Then, make a new recording to see if there&apos;s improvement[1].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Play Word Games&lt;/strong&gt;: Engage in vocabulary games like bingo, Pictionary, or charades using the new words. This helps reinforce the words in a fun and memorable way[2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Challenge Yourself&lt;/strong&gt;: Try to use the new vocabulary in different contexts, such as at home or during other activities. Keep a vocabulary notebook to jot down when you use the words[2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Write Vocabulary Short Stories&lt;/strong&gt;: Create short stories using the new words to show mastery and help remember them in context[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Word of the Week&lt;/strong&gt;: Focus on a few words each week and explore them in depth. Use them in different sentences each day to deepen your understanding[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Million Dollar Word Club&lt;/strong&gt;: Challenge yourself to use a new vocabulary word in class or daily conversation. Recognize each successful use as a personal achievement[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Post-it Stations&lt;/strong&gt;: Place vocabulary words around your study area and write original sentences using those words on sticky notes[4].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By integrating these strategies into your study routine, you will be able to practice and remember the new words more effectively, which will help you use them confidently in conversation.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://ou.edu/content/dam/UniversityCollege/Documents/SLC/5-Day-Study-Plan-8-Week-Courses.pdf&quot;&gt;https://ou.edu/content/dam/UniversityCollege/Documents/SLC/5-Day-Study-Plan-8-Week-Courses.pdf&lt;/a&gt;
[2] &lt;a href=&quot;https://www.apu.apus.edu/docs/shared/course-syllabus/PSYC432.pdf&quot;&gt;https://www.apu.apus.edu/docs/shared/course-syllabus/PSYC432.pdf&lt;/a&gt;
[3] &lt;a href=&quot;https://www.eslkidstuff.com/esl-kids-lesson-plans.html&quot;&gt;https://www.eslkidstuff.com/esl-kids-lesson-plans.html&lt;/a&gt;
[4] &lt;a href=&quot;https://missionbibleclass.org/old-testament/part1/creation-through-noah/day-6-god-created-animals-and-people/&quot;&gt;https://missionbibleclass.org/old-testament/part1/creation-through-noah/day-6-god-created-animals-and-people/&lt;/a&gt;
[5] &lt;a href=&quot;https://www.patenteducationseries.com/study-plans/8-week-study-plan.pdf&quot;&gt;https://www.patenteducationseries.com/study-plans/8-week-study-plan.pdf&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 50 of learning English</title><link>https://blog.ithuo.net/posts/day-50-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-50-of-learning-english/</guid><pubDate>Fri, 19 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the fifth day of Week 8, you should focus on speaking exercises to improve your fluency and pronunciation. Here&apos;s a detailed plan:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Speaking Exercises&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start by reviewing the vocabulary you&apos;ve learned over the past four days. Practice saying each word out loud, focusing on pronunciation and intonation.&lt;/li&gt;
&lt;li&gt;Choose a topic related to software technology or daily life and prepare a short presentation or speech in English. Use as many of the new vocabulary words as you can.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Pronunciation Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Practice the pronunciation of difficult words or sounds. You can use online resources or language learning apps that provide feedback on pronunciation.&lt;/li&gt;
&lt;li&gt;Record yourself speaking in English. Listen to the recording and identify areas for improvement.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Conversation Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If possible, arrange a conversation practice with a native English speaker. This could be a language exchange partner, a tutor, or a friend. Use the new vocabulary words in your conversation.&lt;/li&gt;
&lt;li&gt;If a conversation partner is not available, simulate a conversation by responding to prompts or questions. Record your responses and listen to them for self-evaluation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Review&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the vocabulary you&apos;ve learned over the past four days. Try to use these words in your speaking exercises.&lt;/li&gt;
&lt;li&gt;Review the notes from your listening exercises. Try to incorporate the phrases and sentence structures you&apos;ve learned into your speaking practice.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Verification&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;At the end of the day, record a summary of what you&apos;ve learned and practiced. This will help you to consolidate your learning and practice output, which is crucial for language acquisition.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By engaging in these activities, you will enhance your speaking skills, expand your vocabulary, and improve your pronunciation, all of which are essential for achieving conversational fluency in English[1][4].&lt;/p&gt;
&lt;p&gt;The learning objectives for the fifth day of the eighth week are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Speaking Fluency&lt;/strong&gt;: Improve your ability to express thoughts, ideas, and facts in English in a clear, organized, and detailed manner. This includes using the new vocabulary you&apos;ve learned over the past four days.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pronunciation&lt;/strong&gt;: Enhance your pronunciation skills to ensure that your spoken English is understood by others. This includes working on specific sounds that may be difficult, as well as intonation and stress patterns in English.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conversation Skills&lt;/strong&gt;: Develop your ability to participate in a conversation in English. This includes both understanding what is being said to you and responding appropriately.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Confidence Building&lt;/strong&gt;: Build your confidence in speaking English. This includes overcoming any nervousness or hesitation you may feel when speaking English, especially with native speakers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review and Consolidation&lt;/strong&gt;: Review the vocabulary and listening skills you&apos;ve learned over the past four days and consolidate this knowledge through speaking practice[1][2][3].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://library.ndsu.edu/ir/bitstream/handle/10365/23230/hedtke_the%20four-day%20versus%20the%20five-day%20school%20week.pdf?sequence=1&quot;&gt;https://library.ndsu.edu/ir/bitstream/handle/10365/23230/hedtke_the four-day versus the five-day school week.pdf?sequence=1&lt;/a&gt;
[2] &lt;a href=&quot;https://www.patenteducationseries.com/study-plans/8-week-study-plan.pdf&quot;&gt;https://www.patenteducationseries.com/study-plans/8-week-study-plan.pdf&lt;/a&gt;
[3] &lt;a href=&quot;https://ou.edu/content/dam/UniversityCollege/Documents/SLC/5-Day-Study-Plan-8-Week-Courses.pdf&quot;&gt;https://ou.edu/content/dam/UniversityCollege/Documents/SLC/5-Day-Study-Plan-8-Week-Courses.pdf&lt;/a&gt;
[4] &lt;a href=&quot;https://www.youtube.com/watch?v=6IANEgOBXi0&quot;&gt;https://www.youtube.com/watch?v=6IANEgOBXi0&lt;/a&gt;
[5] &lt;a href=&quot;https://www.dshs.texas.gov/sites/default/files/wellness/PDF/FIVEADAY%20complete.pdf&quot;&gt;https://www.dshs.texas.gov/sites/default/files/wellness/PDF/FIVEADAY complete.pdf&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 49 of learning English</title><link>https://blog.ithuo.net/posts/day-49-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-49-of-learning-english/</guid><pubDate>Thu, 18 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the fourth day of Week 8, you should focus on listening exercises to improve your comprehension and familiarize yourself with different accents and speaking styles. Here&apos;s a detailed plan:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Listening Exercises&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Select two English-language podcasts or videos related to software technology and daily life. Choose content that is slightly above your current level of understanding to challenge yourself.&lt;/li&gt;
&lt;li&gt;Listen to each podcast or video carefully, trying to understand as much as possible. Pause and replay sections if necessary.&lt;/li&gt;
&lt;li&gt;Write down any new vocabulary or phrases you hear and look up their meanings.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Active Listening and Note-Taking&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Practice active listening by summarizing the main points of what you&apos;ve heard. This can be done either in writing or orally.&lt;/li&gt;
&lt;li&gt;Take detailed notes on key concepts, new terminology, and any questions that arise during your listening practice.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Pronunciation Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Repeat after the speakers in the podcasts or videos to practice pronunciation. Focus on intonation, stress, and rhythm.&lt;/li&gt;
&lt;li&gt;Record yourself speaking some of the sentences or phrases you&apos;ve heard. Compare your pronunciation to that of the native speakers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Review&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the vocabulary you&apos;ve learned over the past three days. Try to identify and understand these words in the context of what you&apos;ve listened to.&lt;/li&gt;
&lt;li&gt;Use the new vocabulary in sentences to reinforce your understanding and memory.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Verification&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;At the end of the day, summarize one of the podcasts or videos you listened to in English. This will help you to consolidate your learning and practice output, which is crucial for language acquisition.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By engaging in these activities, you will enhance your listening skills, expand your vocabulary, and improve your pronunciation, all of which are essential for achieving conversational fluency in English.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://ou.edu/content/dam/UniversityCollege/Documents/SLC/5-Day-Study-Plan-8-Week-Courses.pdf&quot;&gt;https://ou.edu/content/dam/UniversityCollege/Documents/SLC/5-Day-Study-Plan-8-Week-Courses.pdf&lt;/a&gt;
[2] &lt;a href=&quot;https://www.patenteducationseries.com/study-plans/8-week-study-plan.pdf&quot;&gt;https://www.patenteducationseries.com/study-plans/8-week-study-plan.pdf&lt;/a&gt;
[3] &lt;a href=&quot;https://www.eslkidstuff.com/esl-kids-lesson-plans.html&quot;&gt;https://www.eslkidstuff.com/esl-kids-lesson-plans.html&lt;/a&gt;
[4] &lt;a href=&quot;https://mygretutor.com/study-plans/eight-week/&quot;&gt;https://mygretutor.com/study-plans/eight-week/&lt;/a&gt;
[5] &lt;a href=&quot;https://www.cmu.edu/teaching/designteach/teach/firstday.html&quot;&gt;https://www.cmu.edu/teaching/designteach/teach/firstday.html&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 48 of learning English</title><link>https://blog.ithuo.net/posts/day-48-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-48-of-learning-english/</guid><pubDate>Wed, 17 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the third day of Week 8, you should continue with vocabulary building and review the material from the previous two days. Here&apos;s a detailed plan:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vocabulary Building and Review&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start by reviewing the 50 new words you learned on Day 1 and Day 2, focusing on their meaning, usage, and pronunciation.&lt;/li&gt;
&lt;li&gt;Learn the final set of 25 new words related to software technology and daily life. Use the same methods as the previous days: flashcards, online vocabulary games, and quizzes.&lt;/li&gt;
&lt;li&gt;Write new sentences with the newly learned words to reinforce their context and usage.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Active Learning Strategies&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Continue with active learning strategies such as creating mind maps of the new vocabulary, grouping words by synonyms or topics, or using the words in a conversation with a study partner or language exchange friend.&lt;/li&gt;
&lt;li&gt;Practice pronunciation of the new words, either with a language learning app that provides feedback or by recording yourself and listening to the playback.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Listening Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Listen to a different English podcast or watch a new video related to software technology and daily life. Pay attention to the usage of the new vocabulary in context.&lt;/li&gt;
&lt;li&gt;Take notes on any additional new words or phrases you encounter and try to incorporate them into your vocabulary practice.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By the end of the day, you should have a solid understanding of the 75 words you&apos;ve studied over the three days and be able to use them in context. This will prepare you for more advanced conversational practice in the following days[1][4].&lt;/p&gt;
&lt;p&gt;Here are 25 new words for you to learn on the third day of Week 8:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Quandary: a state of perplexity or doubt&lt;/li&gt;
&lt;li&gt;Rambunctious: marked by uncontrollable exuberance&lt;/li&gt;
&lt;li&gt;Sardonic: disdainfully or skeptically humorous&lt;/li&gt;
&lt;li&gt;Tautology: needless repetition of an idea, statement, or word&lt;/li&gt;
&lt;li&gt;Ubiquitous: existing or being everywhere at the same time&lt;/li&gt;
&lt;li&gt;Vacillate: to waver in mind, will, or feeling&lt;/li&gt;
&lt;li&gt;Wane: to decrease in size, extent, or degree&lt;/li&gt;
&lt;li&gt;Xenophobia: fear and hatred of strangers or foreigners&lt;/li&gt;
&lt;li&gt;Yore: time past and especially long past&lt;/li&gt;
&lt;li&gt;Zealot: a fervent and even militant proponent of something&lt;/li&gt;
&lt;li&gt;Abate: to decrease in force or intensity&lt;/li&gt;
&lt;li&gt;Bane: a source of harm or ruin&lt;/li&gt;
&lt;li&gt;Cajole: to persuade with flattery or gentle urging&lt;/li&gt;
&lt;li&gt;Daunt: to lessen the courage of&lt;/li&gt;
&lt;li&gt;Ebb: to recede from a flood&lt;/li&gt;
&lt;li&gt;Facetious: joking or jesting often inappropriately&lt;/li&gt;
&lt;li&gt;Glib: marked by ease and informality&lt;/li&gt;
&lt;li&gt;Harbinger: one that initiates a major change&lt;/li&gt;
&lt;li&gt;Iconoclast: one who attacks and seeks to overthrow traditional or popular ideas or institutions&lt;/li&gt;
&lt;li&gt;Juxtapose: to place side by side for comparison or contrast&lt;/li&gt;
&lt;li&gt;Kudos: praise given for achievement&lt;/li&gt;
&lt;li&gt;Lethargic: of, relating to, or characterized by laziness or lack of energy&lt;/li&gt;
&lt;li&gt;Meticulous: marked by extreme care in treatment of details&lt;/li&gt;
&lt;li&gt;Nefarious: flagrantly wicked or impious&lt;/li&gt;
&lt;li&gt;Obfuscate: to make obscure or unclear[1][2][3].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember to understand the meaning, usage, and pronunciation of each word. Try to use them in sentences to better understand their context.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://ou.edu/content/dam/UniversityCollege/Documents/SLC/5-Day-Study-Plan-8-Week-Courses.pdf&quot;&gt;https://ou.edu/content/dam/UniversityCollege/Documents/SLC/5-Day-Study-Plan-8-Week-Courses.pdf&lt;/a&gt;
[2] &lt;a href=&quot;https://www.patenteducationseries.com/study-plans/8-week-study-plan.pdf&quot;&gt;https://www.patenteducationseries.com/study-plans/8-week-study-plan.pdf&lt;/a&gt;
[3] &lt;a href=&quot;https://www.cmu.edu/teaching/designteach/teach/firstday.html&quot;&gt;https://www.cmu.edu/teaching/designteach/teach/firstday.html&lt;/a&gt;
[4] &lt;a href=&quot;https://mygretutor.com/study-plans/eight-week/&quot;&gt;https://mygretutor.com/study-plans/eight-week/&lt;/a&gt;
[5] &lt;a href=&quot;https://www.eslkidstuff.com/esl-kids-lesson-plans.html&quot;&gt;https://www.eslkidstuff.com/esl-kids-lesson-plans.html&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 47 of learning English</title><link>https://blog.ithuo.net/posts/day-47-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-47-of-learning-english/</guid><pubDate>Tue, 16 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the second day of Week 8, you should continue with vocabulary building and review the material from the previous day. Here&apos;s a detailed plan:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vocabulary Building and Review&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start by reviewing the 25 new words you learned on Day 1, focusing on their meaning, usage, and pronunciation.&lt;/li&gt;
&lt;li&gt;Learn another set of 25 new words related to software technology and daily life. Use the same methods as the previous day: flashcards, online vocabulary games, and quizzes.&lt;/li&gt;
&lt;li&gt;Write new sentences with the newly learned words to reinforce their context and usage.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Active Learning Strategies&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Engage in active learning strategies such as creating mind maps of the new vocabulary, grouping words by synonyms or topics, or using the words in a conversation with a study partner or language exchange friend.&lt;/li&gt;
&lt;li&gt;Practice pronunciation of the new words, either with a language learning app that provides feedback or by recording yourself and listening to the playback.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Listening Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Listen to a different English podcast or watch a new video related to software technology and daily life. Pay attention to the usage of the new vocabulary in context.&lt;/li&gt;
&lt;li&gt;Take notes on any additional new words or phrases you encounter and try to incorporate them into your vocabulary practice.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By the end of the day, you should have a solid understanding of the 50 words you&apos;ve studied over the two days and be able to use them in context. This will prepare you for more advanced conversational practice in the following days.&lt;/p&gt;
&lt;p&gt;Here are 25 new words for you to learn on the second day of Week 8:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Incipient: beginning to come into being or to become apparent&lt;/li&gt;
&lt;li&gt;Posse: a group of people who were gathered together by a sheriff in the past to help search for a criminal&lt;/li&gt;
&lt;li&gt;Diligent: characterized by steady, earnest, and energetic effort&lt;/li&gt;
&lt;li&gt;Skulk: to move or hide in a secret way especially because you are planning to do something bad&lt;/li&gt;
&lt;li&gt;Accolade: an expression of praise or admiration&lt;/li&gt;
&lt;li&gt;Circumspect: thinking carefully about possible risks before doing or saying something&lt;/li&gt;
&lt;li&gt;Retronym: a term consisting of a noun and a modifier which specifies the original meaning of the noun&lt;/li&gt;
&lt;li&gt;Ferret: to find and bring to light by searching&lt;/li&gt;
&lt;li&gt;Ominous: suggesting that something bad is going to happen in the future&lt;/li&gt;
&lt;li&gt;Tenet: a belief or idea that is very important to a group&lt;/li&gt;
&lt;li&gt;Mangle: to spoil or ruin (something) with many mistakes&lt;/li&gt;
&lt;li&gt;Elysian: relating to or characteristic of heaven or paradise&lt;/li&gt;
&lt;li&gt;Gargoyle: a grotesquely carved figure of a human or animal&lt;/li&gt;
&lt;li&gt;Cosplay: the activity or practice of dressing up as a character from a work of fiction&lt;/li&gt;
&lt;li&gt;Oneiric: of or relating to dreams&lt;/li&gt;
&lt;li&gt;Bunkum: foolish or untrue words or ideas&lt;/li&gt;
&lt;li&gt;Whinge: to complain in an annoying way&lt;/li&gt;
&lt;li&gt;Axiomatic: self-evident or unquestionable&lt;/li&gt;
&lt;li&gt;Harangue: a lengthy and aggressive speech&lt;/li&gt;
&lt;li&gt;Kindred: one&apos;s family and relations&lt;/li&gt;
&lt;li&gt;Conflate: to combine (two or more texts, ideas, etc.) into one&lt;/li&gt;
&lt;li&gt;Sarcasm: the use of words that mean the opposite of what you really want to say especially in order to insult someone, to show irritation, or to be funny&lt;/li&gt;
&lt;li&gt;Unfettered: not controlled or restricted&lt;/li&gt;
&lt;li&gt;Capitulate: to stop fighting an enemy or opponent&lt;/li&gt;
&lt;li&gt;Inkling: a slight knowledge or suspicion; a hint[2].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember to understand the meaning, usage, and pronunciation of each word. Try to use them in sentences to better understand their context.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.vocabulary.com/lists/299627&quot;&gt;https://www.vocabulary.com/lists/299627&lt;/a&gt;
[2] &lt;a href=&quot;https://www.merriam-webster.com/word-of-the-day/calendar&quot;&gt;https://www.merriam-webster.com/word-of-the-day/calendar&lt;/a&gt;
[3] &lt;a href=&quot;https://www.vocabulary.com/lists/349325&quot;&gt;https://www.vocabulary.com/lists/349325&lt;/a&gt;
[4] &lt;a href=&quot;https://www.merriam-webster.com/vocabulary/weekly-vocabulary-words-for-kids&quot;&gt;https://www.merriam-webster.com/vocabulary/weekly-vocabulary-words-for-kids&lt;/a&gt;
[5] &lt;a href=&quot;https://www.youtube.com/watch?v=aIKltIl5mks&quot;&gt;https://www.youtube.com/watch?v=aIKltIl5mks&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 46 of learning English</title><link>https://blog.ithuo.net/posts/day-46-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-46-of-learning-english/</guid><pubDate>Mon, 15 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the first day of Week 8, you should focus on vocabulary building. Here&apos;s the detailed plan:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learn about 25 new words related to software technology and daily life. You can use flashcards, online vocabulary games, and quizzes to help with this. Make sure you understand the meaning, usage, and pronunciation of each word[2].&lt;/li&gt;
&lt;li&gt;Write sentences using the new words to better understand their context[2].&lt;/li&gt;
&lt;li&gt;Listen to English podcasts or watch videos related to software technology and daily life. Try to understand the content and note down any new words or phrases. This will help improve your listening skills and expose you to different accents and speaking styles[1].&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On the first day of Week 8, you should learn the following words:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Emaciated: very thin especially from disease or hunger or cold&lt;/li&gt;
&lt;li&gt;Surge: rise and move, as in waves or billows&lt;/li&gt;
&lt;li&gt;Aloof: not friendly or outgoing&lt;/li&gt;
&lt;li&gt;Cursory: done or made quickly&lt;/li&gt;
&lt;li&gt;Curtail: to shorten or reduce by cutting off the end or a part of&lt;/li&gt;
&lt;li&gt;Evident: clear to the sight or to the mind&lt;/li&gt;
&lt;li&gt;Juggernaut: something (such as a force, campaign, or movement) that is extremely large and powerful and cannot be stopped&lt;/li&gt;
&lt;li&gt;Minuscule: very small&lt;/li&gt;
&lt;li&gt;Mirth: happiness and laughter&lt;/li&gt;
&lt;li&gt;Nettle: to make (someone) angry[1][2][3].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember to understand the meaning, usage, and pronunciation of each word. Try to use them in sentences to better understand their context.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.vocabulary.com/lists/299627&quot;&gt;https://www.vocabulary.com/lists/299627&lt;/a&gt;
[2] &lt;a href=&quot;https://www.vocabulary.com/lists/349325&quot;&gt;https://www.vocabulary.com/lists/349325&lt;/a&gt;
[3] &lt;a href=&quot;https://www.merriam-webster.com/vocabulary/weekly-vocabulary-words-for-kids&quot;&gt;https://www.merriam-webster.com/vocabulary/weekly-vocabulary-words-for-kids&lt;/a&gt;
[4] &lt;a href=&quot;https://mygretutor.com/study-plans/eight-week/&quot;&gt;https://mygretutor.com/study-plans/eight-week/&lt;/a&gt;
[5] &lt;a href=&quot;https://www.eslkidstuff.com/esl-kids-lesson-plans.html&quot;&gt;https://www.eslkidstuff.com/esl-kids-lesson-plans.html&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 45 of learning English</title><link>https://blog.ithuo.net/posts/day-45-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-45-of-learning-english/</guid><pubDate>Sun, 14 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the fifth day of Week 7, you should focus on expanding your vocabulary and practicing grammar. Here&apos;s a detailed plan:&lt;/p&gt;
&lt;h2&gt;Vocabulary Learning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Days of the Week&lt;/strong&gt;: Continue to practice the days of the week in English. You can use songs, games, and practice using them in sentences[2][5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Word of the Day&lt;/strong&gt;: Continue with the &quot;Word of the Week&quot; series to learn new words. The word for today could be &quot;meticulous,&quot; which means showing great attention to detail; very careful and precise[1].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use Flashcards&lt;/strong&gt;: Continue to use flashcards to study and memorize new words. You can add words related to the days of the week and common phrases used with them[3].&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Grammar Learning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Use Online Resources&lt;/strong&gt;: Continue to use online resources for grammar exercises and explanations. You can focus on sentence construction using the days of the week[1][2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practice Writing&lt;/strong&gt;: Write sentences using the new vocabulary and grammar concepts you&apos;ve learned. Try to use the days of the week in your sentences[1][2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quiz&lt;/strong&gt;: Take a quiz on the days of the week to test your understanding and reinforce your learning[4].&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Verification of Study Results&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Flashcard Tests&lt;/strong&gt;: After studying the flashcards, test your memory by going through the flashcards again and trying to recall the meanings of the words[3].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Writing Assessment&lt;/strong&gt;: Assess your understanding of the new grammar concepts by checking if your sentences are grammatically correct.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conversation Practice&lt;/strong&gt;: Practice using the new vocabulary and grammar concepts in conversations about daily life. This can be done with a language exchange partner, a tutor, or even a language learning app.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;On the fifth day of Week 7, you should continue to practice English grammar with a focus on using the days of the week, time expressions, and prepositions. Here&apos;s how you can do it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Prepositions of Time&lt;/strong&gt;: Practice using prepositions of time such as &quot;on,&quot; &quot;at,&quot; and &quot;in&quot; in sentences. For example, &quot;I have a meeting on Monday,&quot; &quot;I will call you at 5 PM,&quot; or &quot;I go to the gym in the morning.&quot;[1][4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sentence Construction&lt;/strong&gt;: Construct sentences using the days of the week and time expressions. For example, &quot;I have a meeting on Tuesday at 10 AM,&quot; or &quot;I will visit the museum on Thursday afternoon.&quot;[1][2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Writing Practice&lt;/strong&gt;: Write a short paragraph planning your week, using the days of the week and time expressions to describe your activities. For instance, &quot;This week, I will start a new book on Tuesday evening and have dinner with friends on Friday at 7 PM.&quot;[1][2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quiz&lt;/strong&gt;: Take a quiz on the days of the week to test your understanding and reinforce your learning[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interactive Activities&lt;/strong&gt;: Engage in interactive activities such as playing Hangman with the days of the week or chanting a song with a friend, inserting different phrases with each day[2][3].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Real-life Application&lt;/strong&gt;: Make real-life plans using the days of the week and time expressions, such as scheduling appointments or making reservations, and communicate these plans to others[1][2].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By using these methods, you&apos;ll be able to practice both vocabulary (days of the week and time expressions) and grammar (sentence structure and prepositions) effectively. Remember to check your sentences for correct grammar and try to use the new structures in conversation with others to reinforce your learning.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.berlitz.com/blog/days-of-the-week-english&quot;&gt;https://www.berlitz.com/blog/days-of-the-week-english&lt;/a&gt;
[2] &lt;a href=&quot;https://blog.lingoda.com/en/days-of-the-week-in-english/&quot;&gt;https://blog.lingoda.com/en/days-of-the-week-in-english/&lt;/a&gt;
[3] &lt;a href=&quot;https://www.teacherspayteachers.com/browse?search=5%20a%20day%20grammar&quot;&gt;https://www.teacherspayteachers.com/browse?search=5+a+day+grammar&lt;/a&gt;
[4] &lt;a href=&quot;https://promova.com/quiz/days-of-the-week-quiz&quot;&gt;https://promova.com/quiz/days-of-the-week-quiz&lt;/a&gt;
[5] &lt;a href=&quot;https://www.lingobest.com/free-online-english-course/learn-days-week-english/&quot;&gt;https://www.lingobest.com/free-online-english-course/learn-days-week-english/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Week 7 of learning English</title><link>https://blog.ithuo.net/posts/week-7-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/week-7-of-learning-english/</guid><pubDate>Sat, 13 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the fourth day of Week 7, you should continue to practice English grammar with a focus on using the days of the week and time expressions. Here&apos;s how you can do it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Sentence Construction&lt;/strong&gt;: Practice using the days of the week and time expressions in sentences. For example, &quot;I have a meeting on Tuesday at 10 AM,&quot; or &quot;I will visit the museum on Thursday afternoon.&quot;[1][2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Writing Practice&lt;/strong&gt;: Write a short paragraph planning your week, using the days of the week and time expressions to describe your activities. For instance, &quot;This week, I will start a new book on Tuesday evening and have dinner with friends on Friday at 7 PM.&quot;[1][2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Listening and Pronunciation&lt;/strong&gt;: Watch educational videos or listen to songs that teach the days of the week and time expressions to improve your pronunciation and reinforce their spelling and sequence[3][4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interactive Activities&lt;/strong&gt;: Engage in interactive activities such as playing Hangman with the days of the week or chanting a song with a friend, inserting different phrases with each day[2][3].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Real-life Application&lt;/strong&gt;: Make real-life plans using the days of the week and time expressions, such as scheduling appointments or making reservations, and communicate these plans to others[1][2].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;On the fourth day of Week 7, you can practice English grammar by focusing on the following areas:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Time Prepositions&lt;/strong&gt;: Practice using prepositions that relate to time, such as &quot;on,&quot; &quot;at,&quot; and &quot;in.&quot; For example, &quot;I have a meeting on Monday,&quot; &quot;I will call you at 5 PM,&quot; or &quot;I go to the gym in the morning.&quot;[2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adverbs&lt;/strong&gt;: Continue to work on adverbs, especially those that describe the frequency of activities. Examples include &quot;usually,&quot; &quot;sometimes,&quot; &quot;often,&quot; &quot;rarely,&quot; and &quot;never.&quot; Use them in sentences like &quot;I usually go to bed at 11 PM&quot; or &quot;I rarely eat out on weekdays.&quot;[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Passive Voice&lt;/strong&gt;: Practice forming sentences in the passive voice, which is often used in formal or written English. For example, &quot;The project will be completed by Friday,&quot; or &quot;The meeting was canceled due to unforeseen circumstances.&quot;[2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modal Verbs&lt;/strong&gt;: Work on modal verbs of ability (can, could), obligation (must, have to), and probability (might, may). For instance, &quot;I can meet you on Thursday,&quot; or &quot;You must submit the report by Wednesday.&quot;[2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reported Speech&lt;/strong&gt;: Practice transforming direct speech into reported speech. For example, if someone says, &quot;I am busy on Tuesday,&quot; you could report it as &quot;He said he was busy on Tuesday.&quot;[2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Relative Clauses&lt;/strong&gt;: Learn how to use defining relative clauses to provide essential information about a noun. For example, &quot;The person who called you on Tuesday is my manager,&quot; or &quot;The report that was submitted on Monday has some errors.&quot;[2].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To practice these grammar points, you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Complete online exercises and quizzes from resources like Perfect English Grammar[2].&lt;/li&gt;
&lt;li&gt;Write sentences or short paragraphs using the grammar concepts you are focusing on.&lt;/li&gt;
&lt;li&gt;Get feedback on your writing from a tutor or through online platforms.&lt;/li&gt;
&lt;li&gt;Try to use these grammar structures in your daily conversations or in writing emails and messages.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By practicing these specific grammar points, you will improve your understanding and usage of English grammar, which will help you communicate more effectively.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.test-guide.com/english-grammar-practice-tests.html&quot;&gt;https://www.test-guide.com/english-grammar-practice-tests.html&lt;/a&gt;
[2] &lt;a href=&quot;https://www.perfect-english-grammar.com/grammar-exercises.html&quot;&gt;https://www.perfect-english-grammar.com/grammar-exercises.html&lt;/a&gt;
[3] &lt;a href=&quot;https://www.teachercreatedmaterials.com/p/daily-language-practice-for-second-grade-week-7/51167_07/&quot;&gt;https://www.teachercreatedmaterials.com/p/daily-language-practice-for-second-grade-week-7/51167_07/&lt;/a&gt;
[4] &lt;a href=&quot;https://elt.oup.com/student/practicegrammar/advanced/a_testzone/?cc=us&amp;amp;selLanguage=en&quot;&gt;https://elt.oup.com/student/practicegrammar/advanced/a_testzone/?cc=us&amp;amp;selLanguage=en&lt;/a&gt;
[5] &lt;a href=&quot;https://www.teacherspayteachers.com/Product/Adverbs-Grammar-Language-Week-7-Digital-Paper-7262599&quot;&gt;https://www.teacherspayteachers.com/Product/Adverbs-Grammar-Language-Week-7-Digital-Paper-7262599&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 44 of learning English</title><link>https://blog.ithuo.net/posts/day-44-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-44-of-learning-english/</guid><pubDate>Fri, 12 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the third day of Week 7, you should continue to build on your vocabulary and grammar skills. Here&apos;s a detailed plan:&lt;/p&gt;
&lt;h2&gt;Vocabulary Learning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Days of the Week&lt;/strong&gt;: Continue to practice the days of the week in English. You can use songs, games, and practice using them in sentences[3][4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use Flashcards&lt;/strong&gt;: Continue to use flashcards to study and memorize new words. You can add words related to the days of the week and common phrases used with them[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Word of the Day&lt;/strong&gt;: Continue with the &quot;Word of the Day&quot; series to learn new words[2].&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Grammar Learning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Use Online Resources&lt;/strong&gt;: Continue to use online resources for grammar exercises and explanations. You can focus on sentence construction using the days of the week[1][2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practice Writing&lt;/strong&gt;: Write sentences using the new vocabulary and grammar concepts you&apos;ve learned. Try to use the days of the week in your sentences[1][2].&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Verification of Study Results&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Flashcard Tests&lt;/strong&gt;: After studying the flashcards, test your memory by going through the flashcards again and trying to recall the meanings of the words[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Writing Assessment&lt;/strong&gt;: Assess your understanding of the new grammar concepts by checking if your sentences are grammatically correct.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conversation Practice&lt;/strong&gt;: Practice using the new vocabulary and grammar concepts in conversations about daily life. This can be done with a language exchange partner, a tutor, or even a language learning app.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;On the third day of Week 7, you should focus on expanding your vocabulary with new words and phrases, as well as reinforcing your understanding of the days of the week. Here are some specific words and phrases to learn:&lt;/p&gt;
&lt;h2&gt;Vocabulary Words&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Superfluous&lt;/strong&gt;: This word means unnecessary, especially through being more than enough. The word of the week from the YouTube video can be used in a sentence like &quot;The report was filled with superfluous details that were not relevant to the conclusion.&quot;[2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Days of the Week&lt;/strong&gt;: Make sure you are comfortable with the names of the days of the week: Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, and Sunday. Use them in sentences to plan your week or talk about your schedule[4].&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Phrases&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&quot;The meeting on &lt;strong&gt;Tuesday&lt;/strong&gt; is superfluous since we already discussed everything via email.&quot;&lt;/li&gt;
&lt;li&gt;&quot;I find it superfluous to have a meeting every &lt;strong&gt;Monday&lt;/strong&gt; when a simple memo could suffice.&quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Grammar&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Using Days of the Week in Sentences&lt;/strong&gt;: Practice using the days of the week in context. For example, &quot;I will go to the gym on &lt;strong&gt;Wednesday&lt;/strong&gt; and &lt;strong&gt;Friday&lt;/strong&gt;.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adjectives and Adverbs&lt;/strong&gt;: Use adjectives and adverbs to describe activities or things associated with specific days. For example, &quot;I have a busy &lt;strong&gt;Monday&lt;/strong&gt; ahead,&quot; or &quot;She usually works late on &lt;strong&gt;Thursdays&lt;/strong&gt;.&quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember to practice these words and phrases in writing and speaking. You can write sentences or short paragraphs using the new vocabulary and days of the week, and try to use them in conversations with others or in language learning apps. This will help you to memorize and understand how to use them correctly in context.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.teachercreatedmaterials.com/p/daily-language-practice-for-second-grade-week-7/51167_07/&quot;&gt;https://www.teachercreatedmaterials.com/p/daily-language-practice-for-second-grade-week-7/51167_07/&lt;/a&gt;
[2] &lt;a href=&quot;https://www.youtube.com/watch?v=655wCK8ijpc&quot;&gt;https://www.youtube.com/watch?v=655wCK8ijpc&lt;/a&gt;
[3] &lt;a href=&quot;https://www.gamutspanish.com/week-7.html&quot;&gt;https://www.gamutspanish.com/week-7.html&lt;/a&gt;
[4] &lt;a href=&quot;https://www.youtube.com/watch?v=6IANEgOBXi0&quot;&gt;https://www.youtube.com/watch?v=6IANEgOBXi0&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 42 of learning English</title><link>https://blog.ithuo.net/posts/day-42-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-42-of-learning-english/</guid><pubDate>Thu, 11 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the second day of Week 7, you can continue to focus on both vocabulary and grammar. Here&apos;s a detailed plan:&lt;/p&gt;
&lt;h2&gt;Vocabulary Learning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Days of the Week&lt;/strong&gt;: As per the search results, learning the days of the week is essential for any language learner. You can learn the seven days of the week through songs, games, and practice using them in sentences[1][2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use Flashcards&lt;/strong&gt;: Continue to use flashcards to study and memorize new words. You can add words related to the days of the week and common phrases used with them[1].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Word of the Day&lt;/strong&gt;: Continue with the &quot;Word of the Day&quot; series to learn new words[2].&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Grammar Learning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Use Online Resources&lt;/strong&gt;: Continue to use online resources for grammar exercises and explanations. You can focus on sentence construction using the days of the week[1][2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practice Writing&lt;/strong&gt;: Write sentences using the new vocabulary and grammar concepts you&apos;ve learned. Try to use the days of the week in your sentences[1][2].&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Verification of Study Results&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Flashcard Tests&lt;/strong&gt;: After studying the flashcards, test your memory by going through the flashcards again and trying to recall the meanings of the words[1].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Writing Assessment&lt;/strong&gt;: Assess your understanding of the new grammar concepts by checking if your sentences are grammatically correct.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conversation Practice&lt;/strong&gt;: Practice using the new vocabulary and grammar concepts in conversations about daily life. This can be done with a language exchange partner, a tutor, or even a language learning app.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember, consistency is key in language learning. Try to dedicate a specific amount of time each day to studying English, and gradually increase the intensity of your studies as your proficiency improves.&lt;/p&gt;
&lt;p&gt;Based on the search results, here are the specific words, phrases, and grammar concepts you should focus on for the second day of Week 7:&lt;/p&gt;
&lt;h2&gt;Vocabulary&lt;/h2&gt;
&lt;p&gt;From the Quizlet flashcards[1][3], you should memorize the following words:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Implacable&lt;/li&gt;
&lt;li&gt;Jurisdiction&lt;/li&gt;
&lt;li&gt;Paroxysm&lt;/li&gt;
&lt;li&gt;Harass&lt;/li&gt;
&lt;li&gt;Monolithic&lt;/li&gt;
&lt;li&gt;Indigent&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Try to understand the meaning of each word, how it is used in a sentence, and its synonyms and antonyms if applicable.&lt;/p&gt;
&lt;h2&gt;Phrases&lt;/h2&gt;
&lt;p&gt;From the daily language practice[2], you should focus on phrases that incorporate the vocabulary words you are learning. For example:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&quot;The judge has jurisdiction over these cases.&quot;&lt;/li&gt;
&lt;li&gt;&quot;The patient had a paroxysm of coughing.&quot;&lt;/li&gt;
&lt;li&gt;&quot;The company has a monolithic corporate culture.&quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Grammar&lt;/h2&gt;
&lt;p&gt;The grammar concept for this week is adverbs[5]. Adverbs are words that modify a verb, an adjective, or another adverb. They often tell us how, when, where, why, or to what extent something happens or is done. For example:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&quot;He runs quickly.&quot; (Here, &quot;quickly&quot; is an adverb modifying the verb &quot;runs.&quot;)&lt;/li&gt;
&lt;li&gt;&quot;She is extremely happy.&quot; (Here, &quot;extremely&quot; is an adverb modifying the adjective &quot;happy.&quot;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You should focus on understanding what adverbs are, how they are used in sentences, and how they can change the meaning of a sentence. Practice identifying adverbs in sentences and using them in your own writing.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://quizlet.com/76354143/week-7-day-1-sentences-flash-cards/&quot;&gt;https://quizlet.com/76354143/week-7-day-1-sentences-flash-cards/&lt;/a&gt;
[2] &lt;a href=&quot;https://www.teachercreatedmaterials.com/p/daily-language-practice-for-second-grade-week-7/51167_07/&quot;&gt;https://www.teachercreatedmaterials.com/p/daily-language-practice-for-second-grade-week-7/51167_07/&lt;/a&gt;
[3] &lt;a href=&quot;https://quizlet.com/381217205/week-7-day-2-flash-cards/&quot;&gt;https://quizlet.com/381217205/week-7-day-2-flash-cards/&lt;/a&gt;
[4] &lt;a href=&quot;https://www.ef.edu/blog/language/how-to-memorize-new-vocabulary-faster/&quot;&gt;https://www.ef.edu/blog/language/how-to-memorize-new-vocabulary-faster/&lt;/a&gt;
[5] &lt;a href=&quot;https://www.teacherspayteachers.com/Product/Adverbs-Grammar-Language-Week-7-Digital-Paper-7262599&quot;&gt;https://www.teacherspayteachers.com/Product/Adverbs-Grammar-Language-Week-7-Digital-Paper-7262599&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 41 of learning English</title><link>https://blog.ithuo.net/posts/day-41-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-41-of-learning-english/</guid><pubDate>Wed, 10 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the first day of Week 7, you can focus on both vocabulary and grammar. Here&apos;s a detailed plan:&lt;/p&gt;
&lt;h2&gt;Vocabulary Learning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Use Flashcards&lt;/strong&gt;: Use online platforms like Quizlet to study and memorize flashcards. For example, you can start with the flashcards containing terms like &quot;Implacable&quot;, &quot;Jurisdiction&quot;, &quot;Paroxysm&quot; and more[1].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Learn a Word of the Day&lt;/strong&gt;: You can follow a &quot;Word of the Day&quot; series on platforms like YouTube to learn new words. For instance, the word &quot;Superfluous&quot; is the word of the week in one of the episodes[2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Specialized and Academic Vocabulary&lt;/strong&gt;: If you&apos;re interested in software technology, you can start learning specialized vocabulary related to this field. Open University provides resources for learning new specialized and academic vocabulary[3].&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Grammar Learning&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Use Online Resources&lt;/strong&gt;: There are numerous online resources that provide grammar exercises and explanations. You can dedicate a portion of your study time to learning a new grammar concept and practicing it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practice Writing&lt;/strong&gt;: Writing sentences using the new vocabulary and grammar concepts you&apos;ve learned can help reinforce your understanding. You can write a short paragraph or a few sentences every day.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Verification of Study Results&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Flashcard Tests&lt;/strong&gt;: After studying the flashcards, you can test your memory by going through the flashcards again and trying to recall the meanings of the words[1].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Writing Assessment&lt;/strong&gt;: You can assess your understanding of the new grammar concepts by checking if your sentences are grammatically correct.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conversation Practice&lt;/strong&gt;: You can practice using the new vocabulary and grammar concepts in conversations about software technology or daily life. This can be done with a language exchange partner, a tutor, or even a language learning app.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember, consistency is key in language learning. Try to dedicate a specific amount of time each day to studying English, and gradually increase the intensity of your studies as your proficiency improves.&lt;/p&gt;
&lt;p&gt;Here are some effective ways to practice speaking English on a limited schedule:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Set aside dedicated time&lt;/strong&gt;: Treat your English practice like an important appointment. Even if it&apos;s just 15-30 minutes a day, consistent practice is key[2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use technology and online resources&lt;/strong&gt;: Language learning apps offer convenient ways to practice speaking with native speakers. You can also use English pronunciation apps[3][4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Find a language buddy or study group&lt;/strong&gt;: Having someone to practice with regularly can provide accountability and motivation. Schedule regular meetups or online sessions where you can have conversations[2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integrate English into your everyday life&lt;/strong&gt;: Listen to English podcasts during your commute, watch movies or TV shows in English with subtitles, or even think and talk to yourself in English throughout the day[2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Talk to yourself in English&lt;/strong&gt;: This can help you get used to speaking the language and can be done whenever you have some free time[3].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use English in real-life situations&lt;/strong&gt;: Try to use English in your daily life as much as possible. For example, you could order food in English, ask for directions, or have a conversation with a friend[1].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Participate in public speaking events&lt;/strong&gt;: If possible, participate in events like open debates, spoken word readings, and improvised storytelling gatherings. These are places where you can practice speaking English[3].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Narrate your world&lt;/strong&gt;: Describe what you&apos;re doing or planning to do in English. This can be done silently or out loud[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sing along to English songs&lt;/strong&gt;: This is a fun way to improve your pronunciation and fluency[4].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember, the key to improving your English speaking skills is regular and consistent practice. Even if you only have a limited amount of time each day, making the most of that time can lead to significant improvements.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://quizlet.com/76354143/week-7-day-1-sentences-flash-cards/&quot;&gt;https://quizlet.com/76354143/week-7-day-1-sentences-flash-cards/&lt;/a&gt;
[2] &lt;a href=&quot;https://www.youtube.com/watch?v=655wCK8ijpc&quot;&gt;https://www.youtube.com/watch?v=655wCK8ijpc&lt;/a&gt;
[3] &lt;a href=&quot;https://www.open.edu/openlearn/mod/oucontent/view.php?id=19205&amp;amp;printable=1&quot;&gt;https://www.open.edu/openlearn/mod/oucontent/view.php?id=19205&amp;amp;printable=1&lt;/a&gt;
[4] &lt;a href=&quot;https://quizlet.com/381217205/week-7-day-2-flash-cards/&quot;&gt;https://quizlet.com/381217205/week-7-day-2-flash-cards/&lt;/a&gt;
[5] &lt;a href=&quot;https://www.gamutspanish.com/week-7.html&quot;&gt;https://www.gamutspanish.com/week-7.html&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 40 of learning English</title><link>https://blog.ithuo.net/posts/day-40-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-40-of-learning-english/</guid><pubDate>Tue, 09 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dear Derick,&lt;/p&gt;
&lt;p&gt;On the seventh day of Week 6, to effectively practice English grammar, consider the following strategies:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Reading&lt;/strong&gt;: Spend time reading English texts, which can reinforce correct grammar usage. Choose materials that interest you to make the practice enjoyable[3].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grammar Games and Exercises&lt;/strong&gt;: Engage in grammar games and exercises available online. These can provide a fun way to test your knowledge and reinforce learning. Set aside time each day to complete these exercises[3].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review the Basics&lt;/strong&gt;: Go back over the basic grammar rules and principles. This could involve revisiting notes from previous lessons or using grammar books and online resources to solidify your understanding[3].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Listen and Learn&lt;/strong&gt;: Pay attention to feedback from instructors or language partners. If you have consistent issues with certain grammar topics, focus on those areas for improvement[3].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practical Application&lt;/strong&gt;: Use the grammar points you&apos;ve learned in writing or speaking exercises. For example, write a short story using the past perfect and future perfect tenses or describe your plans for the next week using the future perfect continuous tense[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Peer Review&lt;/strong&gt;: If possible, have someone else review your grammar usage in writing or speaking. This could be a language exchange partner, tutor, or fellow learner. They can provide valuable feedback and help you correct mistakes[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mini Grammar Lessons&lt;/strong&gt;: Incorporate mini grammar lessons into your daily activities. For example, while reading aloud or writing, pause to identify and discuss the grammar structures being used[5].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By incorporating these strategies into your study routine, you will continue to improve your grammar skills and gain confidence in using English correctly in various contexts.&lt;/p&gt;
&lt;p&gt;Best,
Judy&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.berlitz.com/blog/days-of-the-week-english&quot;&gt;https://www.berlitz.com/blog/days-of-the-week-english&lt;/a&gt;
[2] &lt;a href=&quot;https://www.edweek.org/teaching-learning/opinion-seven-strategies-for-grammar-instruction/2021/06&quot;&gt;https://www.edweek.org/teaching-learning/opinion-seven-strategies-for-grammar-instruction/2021/06&lt;/a&gt;
[3] &lt;a href=&quot;https://www.varsitytutors.com/blog/7+tips+to+improve+your+grammar+skills&quot;&gt;https://www.varsitytutors.com/blog/7+tips+to+improve+your+grammar+skills&lt;/a&gt;
[4] &lt;a href=&quot;https://www.wikihow.com/Teach-Your-Child-the-Days-of-the-Week&quot;&gt;https://www.wikihow.com/Teach-Your-Child-the-Days-of-the-Week&lt;/a&gt;
[5] &lt;a href=&quot;https://thebutterflyteacher.com/easy-ways-to-teach-grammar/&quot;&gt;https://thebutterflyteacher.com/easy-ways-to-teach-grammar/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 39 of learning English</title><link>https://blog.ithuo.net/posts/day-39-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-39-of-learning-english/</guid><pubDate>Mon, 08 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dear Derick,&lt;/p&gt;
&lt;p&gt;On the sixth day of Week 6, to effectively consolidate your learning of vocabulary and grammar, you should engage in the following activities:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vocabulary Learning&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Review&lt;/strong&gt;: Start by reviewing the words you have learned throughout the week. This helps reinforce your memory and understanding of the words[1].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vocabulary Games&lt;/strong&gt;: Engage in vocabulary games such as Trashketball, Pop, or Charades to make the review process fun and interactive. Games can help solidify your recall of the words in an enjoyable way[1].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Self-Assessment&lt;/strong&gt;: Use a self-assessment scale to gauge your comfort level with each word. This will help you identify which words you need to spend more time on[3].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use in Context&lt;/strong&gt;: Try to use the new vocabulary in conversations or writing exercises. This practical application helps integrate the words into your active vocabulary[3].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Grammar Learning&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Grammar Review&lt;/strong&gt;: Review the past perfect and future perfect tenses that you have been practicing. Go over your notes and example sentences to reinforce your understanding[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grammar Exercises&lt;/strong&gt;: Complete grammar exercises that challenge you to use the past perfect and future perfect tenses in context. This could include fill-in-the-blank activities or sentence rewriting[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practical Application&lt;/strong&gt;: Use the grammar points in speaking or writing. Create scenarios where you would naturally use these tenses, such as describing past experiences or future plans[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Peer Review&lt;/strong&gt;: If possible, have a study partner or tutor review your sentences to provide feedback. This can help you correct any mistakes and improve your usage of the grammar points[5].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By engaging in these activities, you will reinforce the vocabulary and grammar you have learned throughout the week, making it easier to remember and use them correctly in conversation.&lt;/p&gt;
&lt;p&gt;Dear Derick,&lt;/p&gt;
&lt;p&gt;On the sixth day of Week 6, here are the new words and grammar points you should focus on:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vocabulary Learning&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Based on the vocabulary list provided in the search results[5], here are 20 new words you should learn:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Ambiguous&lt;/li&gt;
&lt;li&gt;Complement&lt;/li&gt;
&lt;li&gt;Discrepancy&lt;/li&gt;
&lt;li&gt;Fluctuate&lt;/li&gt;
&lt;li&gt;Inhibit&lt;/li&gt;
&lt;li&gt;Predominant&lt;/li&gt;
&lt;li&gt;Subsequent&lt;/li&gt;
&lt;li&gt;Accumulate&lt;/li&gt;
&lt;li&gt;Constrain&lt;/li&gt;
&lt;li&gt;Diminish&lt;/li&gt;
&lt;li&gt;Emerge&lt;/li&gt;
&lt;li&gt;Inevitable&lt;/li&gt;
&lt;li&gt;Preliminary&lt;/li&gt;
&lt;li&gt;Summarize&lt;/li&gt;
&lt;li&gt;Adjacent&lt;/li&gt;
&lt;li&gt;Commodity&lt;/li&gt;
&lt;li&gt;Discrete&lt;/li&gt;
&lt;li&gt;Exclude&lt;/li&gt;
&lt;li&gt;Inherent&lt;/li&gt;
&lt;li&gt;Prospect&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For each word, understand its meaning, pronunciation, and usage in a sentence. You can use the context clues provided in the sentences from the vocabulary list[5] to understand how each word is used.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Grammar Learning&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;On the sixth day, continue with the future perfect continuous tense. This tense is used to describe an action that will begin in the future and is expected to continue until some time in the future[2][3]. Practice constructing sentences using this tense, such as &quot;By the end of this year, I will have been studying English for 12 months.&quot;&lt;/p&gt;
&lt;p&gt;Also, introduce the past perfect continuous tense. This tense is used to describe an action that began and continued in the past until another action occurred[2][3]. Practice constructing sentences using this tense, such as &quot;I had been studying English for two hours when Judy called.&quot;&lt;/p&gt;
&lt;p&gt;Remember to review these words and the grammar point several times throughout the day to help you remember them.&lt;/p&gt;
&lt;p&gt;Best,
Judy&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.clozemaster.com/blog/vocabulary-or-grammar/&quot;&gt;https://www.clozemaster.com/blog/vocabulary-or-grammar/&lt;/a&gt;
[2] &lt;a href=&quot;https://www.reading.ac.uk/global-study-lounge/eap/vocabulary-grammar&quot;&gt;https://www.reading.ac.uk/global-study-lounge/eap/vocabulary-grammar&lt;/a&gt;
[3] &lt;a href=&quot;https://learnenglishkids.britishcouncil.org/grammar-vocabulary&quot;&gt;https://learnenglishkids.britishcouncil.org/grammar-vocabulary&lt;/a&gt;
[4] &lt;a href=&quot;https://www.britishcouncil.org/voices-magazine/ten-ways-learn-new-words-language-learner&quot;&gt;https://www.britishcouncil.org/voices-magazine/ten-ways-learn-new-words-language-learner&lt;/a&gt;
[5] &lt;a href=&quot;https://languageartsclassroom.com/vocabulary-and-grammar-lesson-10-words/&quot;&gt;https://languageartsclassroom.com/vocabulary-and-grammar-lesson-10-words/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>周报(1.1-1.7)</title><link>https://blog.ithuo.net/posts/weekly-report-1-1-1-7/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/weekly-report-1-1-1-7/</guid><pubDate>Mon, 08 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;表达&lt;/h3&gt;
&lt;p&gt;从22年11月份接触chatgpt后，开始尝试用它当作我的全能助手，工作汇报，邮件内容，PPT总结甚至编码测试方面都在为我提供帮助，但是随着用了一年多，发现自己的语言表达能力似乎在下降，以前还会很费力的去写分享稿，各种说明，现在似乎都交给AI了，似乎有点过度依赖了。在24年的计划中加入发表52篇周报，可能刚开始还是流水账式的，每天要做的事情就那些，不会有太大的变化，但尽量写出自己的感受和看法，并不一定非要输出价值。&lt;/p&gt;
&lt;h3&gt;闲扯&lt;/h3&gt;
&lt;p&gt;上家公司被爆出停发年度绩效，一时间还上了热搜，在脉脉里铺天盖地的吐槽，还有一些朋友问我是怎么回事，虽然我已经很早的离开这家公司，但是呆了五年，有很多好的坏的习惯都是在这家公司养成了，还差不多30块钱买了公司股票，结果亏了51%，不如那时候拿钱全部压上ETH，起码也不会跌这么惨&lt;/p&gt;
&lt;h3&gt;娱乐&lt;/h3&gt;
&lt;p&gt;在关注UFC的战事，很喜欢沙夫卡特这个选手，算是次中的最强了，开始在家里跟着B站一个up猪练习，增加一点运动不是坏处&lt;/p&gt;
&lt;p&gt;看了纸牌屋的前两季，说实话理解了第一季的套路后，剩下的都是在延续，没有推陈出新。&lt;/p&gt;
&lt;p&gt;降低社交，一个季度交流一次就行，人不会在很短时间骤变，吃吃喝喝吹吹牛会让人变得很厌倦，每次都是表演。&lt;/p&gt;
&lt;h3&gt;MSCS&lt;/h3&gt;
&lt;p&gt;从去年开始读了一个美国的CS Master，本周的课程是C++数据处理，提交了四份MSCS作业，我对c/c++表示恐惧，一直写托管的高级语言，在看到低级语言的代码就会产生抗拒心理，沉下心来看其实也不是很难，但是就很抗拒，一方面目前学的课程大部分对以后的职业发展没有直接帮助，另一方面是投入时间不够，还有大量的实践投入到其他方面&lt;/p&gt;
&lt;h3&gt;读书&lt;/h3&gt;
&lt;p&gt;本周读书时长如下，读完的书是诺伯特·维纳的《控制论》，主要研究的是控制系统和反馈机制，通过输入和输出信号之间的反馈机制来控制系统的状态和行为的系统。控制论中的关键概念还包括控制器、传感器、执行器等。控制论的基本原理是反馈控制，反馈控制的优势在于它可以自动调整控制系统的输入信号，以适应系统的实际状态，从而提高系统的稳定性和鲁棒性。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/aa14270526bc4335169dff8ebb75965c.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;AUTOX.js&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/kkevsekk1/AutoX&quot;&gt;kkevsekk1/AutoX: A UiAutomator on android, does not need root access(安卓平台上的JavaScript自动化工具) (github.com)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://doc.autoxjs.com/#/ui&quot;&gt;用户界面 - UI (autoxjs.com)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;autox.js是一个基于JavaScript的移动端自动化工具，无需Root权限，支持悬浮窗录制和运行，适合自动化、工作流工具。它是由kkevsekk1在原作者不再维护Auto.js项目的基础上继续开发的一个分支。它使用Rhino 1.7.13作为脚本引擎，支持ES5和部分ES6特性。&lt;/p&gt;
&lt;p&gt;如果你想下载autox.js的最新版本，你可以访问&lt;a href=&quot;https://github.com/kkevsekk1/AutoX/releases&quot;&gt;这个链接&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;如果你想了解如何用autox.js编写和运行自动化脚本，你可以参考&lt;a href=&quot;https://www.cnblogs.com/ghj1976/p/autoxjs.html&quot;&gt;这篇文章&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;如果你想查看autox.js的源码和文档，你可以访问&lt;a href=&quot;https://github.com/kkevsekk1/AutoX&quot;&gt;这个仓库&lt;/a&gt;。&lt;/p&gt;
&lt;h3&gt;英语学习&lt;/h3&gt;
&lt;p&gt;本周每天都在发英语学习笔记，尽量延续这个习惯，因为基础太差，虽然大部分的英文技术文章可以看懂，但仅限于自己原来使用工具翻译过的内容，这时候就意识到语法的重要性，可能认识90%的单词，如果不明白语法就会理解错误。&lt;/p&gt;
&lt;p&gt;新的一年新的开始，已经在扇贝打卡190天了，过的真快。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/fe73f733bf71c69037a904583c54a65f.jpeg&quot; alt=&quot;Untitled.jpeg&quot; /&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>周报(1.8-1.14)</title><link>https://blog.ithuo.net/posts/weekly-report-1-8-1-14/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/weekly-report-1-8-1-14/</guid><pubDate>Mon, 08 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;随想&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;前三天因为晚上总是失眠，白天就没有精力，再加上人都有惰性，会把时间浪费在快速获得快感的娱乐活动上，比如躺在床上玩手机，刷短视频，但刷短视频并不会带来放松，只是用大量的强刺激信息一直引诱多巴胺持续关注下去，至少带来的危害是增加眼睛近视程度，是不可逆的伤害。&lt;/li&gt;
&lt;li&gt;制定规则在非工作，学习时间不看电子屏幕，并且强制去远眺，放松眼睛，而且不要躺下玩手机，为自己玩手机的想法增加一点困难&lt;/li&gt;
&lt;li&gt;当对未完成事项感到恐惧，认为自己未到达心理预期，从而开始多线程操作，这样会变得更差，甚至每个任务完成的质量都会降低，就会产生深深的焦虑&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;关于AI副业&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://17yongai.com/&quot;&gt;一起用AI | AI副业搞钱套路集合站点 (17yongai.com)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;在23年买了一年的&lt;a href=&quot;https://www.perplexity.ai/&quot;&gt;perplexity&lt;/a&gt; 可以提供软件训练的大模型，也支持GPT4,Claude2.1模型，而且每天有600次提问机会，是完全够用的，支持银联/visa订阅，通过我的&lt;a href=&quot;https://perplexity.ai/pro?referral_code=SGJ7X87B&quot;&gt;邀请链接&lt;/a&gt;可以获得优惠，如果有关于perplexity的问题也可以和我交流。&lt;/p&gt;
&lt;h3&gt;英语学习&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;背单词，通过扇贝的划词记录助手，将阅读文章遇到的生词记录到扇贝生词本中，每天完成打卡，还有一帮准备高考的小朋友一起加油&lt;/li&gt;
&lt;li&gt;学习语法，之前基础太差，能阅读英文技术文章，是经常翻译内容，记住了中文释义，但是换一种表达方式就会产生误解，所以要学习语法，这是语法的重要性&lt;/li&gt;
&lt;li&gt;练习听力，在看纸牌屋的时候，frank的很多次演讲都在认真听，很有感染力&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/da5895b988bff6a21f574a585c6d2544.jpeg&quot; alt=&quot;Untitled.jpeg&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;读书笔记&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/31d710c5c947ffd9cd2bd03a81d9c5d5.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;本周读完的书是《新程序员004：我们的技术时代，我们的程序人生》，这本书讲了大家熟悉的C++之父，C#之父，Mysql之父，VUE创始人尤雨溪，他们对技术的思考，对开源的理解，编程范式以及软件世界对现实世界产生的影响&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Web3&lt;/h3&gt;
&lt;p&gt;在11月份参加&lt;a href=&quot;https://openbuild.xyz/learn/challenges&quot;&gt;open build&lt;/a&gt;的活动，给发了10U的bounty，这些dao组织通过增加外部影响力可以获得社区的捐赠，还去参加了一个制作在线代码编译解释执行的开源团队，使用go编写build pack，用于编译rust的sui链应用&lt;/p&gt;
&lt;p&gt;从7月份开始进入web3后，学到了很多内容，加密，智能合约，如何完成一笔交易，dapp是如何运行在链上的，solidity是一个很好的编程语言，希望能有更多链像evm这样发扬光大&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 38 of learning English</title><link>https://blog.ithuo.net/posts/day-38-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-38-of-learning-english/</guid><pubDate>Sun, 07 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dear Derick,&lt;/p&gt;
&lt;p&gt;On the fifth day of Week 6, here are some effective ways to learn vocabulary and grammar:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vocabulary Learning&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Vocabulary Flashcards&lt;/strong&gt;: Create flashcards for each new word with the word on one side and its meaning, pronunciation, and an example sentence on the other side. Review these flashcards regularly[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Written Repetition&lt;/strong&gt;: Write each new word 10-15 times. This helps you remember the spelling and pronunciation of the words. Saying the words out loud as you write them can also help commit them to memory[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vocabulary Games&lt;/strong&gt;: Play vocabulary games to review the words you&apos;ve learned. Games make learning fun and engaging, which can help you remember the words better[1].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Grammar Learning&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Grammar Exercises&lt;/strong&gt;: Continue practicing the past perfect and future perfect tenses through exercises. This could include fill-in-the-blank activities or sentence transformation exercises[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practical Application&lt;/strong&gt;: Use the grammar points in speaking or writing. For example, describe past experiences using the past perfect tense and narrate future events using the future perfect tense[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review&lt;/strong&gt;: Review the grammar rules and structures you&apos;ve learned. Revisit your notes and practice sentences to reinforce your understanding[5].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember, the key to effective learning is consistency and practice. Review the vocabulary words and grammar points several times throughout the day to help you remember them[1][5].&lt;/p&gt;
&lt;p&gt;On the fourth day of Week 6, here are the new words and grammar points you should focus on:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vocabulary Learning&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Based on the vocabulary list provided in the search results[5], here are 20 new words you should learn:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Ambiguous&lt;/li&gt;
&lt;li&gt;Complement&lt;/li&gt;
&lt;li&gt;Discrepancy&lt;/li&gt;
&lt;li&gt;Fluctuate&lt;/li&gt;
&lt;li&gt;Inhibit&lt;/li&gt;
&lt;li&gt;Predominant&lt;/li&gt;
&lt;li&gt;Subsequent&lt;/li&gt;
&lt;li&gt;Accumulate&lt;/li&gt;
&lt;li&gt;Constrain&lt;/li&gt;
&lt;li&gt;Diminish&lt;/li&gt;
&lt;li&gt;Emerge&lt;/li&gt;
&lt;li&gt;Inevitable&lt;/li&gt;
&lt;li&gt;Preliminary&lt;/li&gt;
&lt;li&gt;Summarize&lt;/li&gt;
&lt;li&gt;Adjacent&lt;/li&gt;
&lt;li&gt;Commodity&lt;/li&gt;
&lt;li&gt;Discrete&lt;/li&gt;
&lt;li&gt;Exclude&lt;/li&gt;
&lt;li&gt;Inherent&lt;/li&gt;
&lt;li&gt;Prospect&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For each word, understand its meaning, pronunciation, and usage in a sentence. You can use the context clues provided in the sentences from the vocabulary list[5] to understand how each word is used.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Grammar Learning&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;On the fourth day, continue with the future perfect tense. This tense is used to describe an action that will have been completed at some point in the future[2][3]. Practice constructing sentences using this tense, such as &quot;I will have learned 60 new words by the end of this week.&quot;&lt;/p&gt;
&lt;p&gt;Also, introduce the future perfect continuous tense. This tense is used to describe an action that will begin in the future and is expected to continue until some time in the future[2][3]. Practice constructing sentences using this tense, such as &quot;By the end of this year, I will have been studying English for 12 months.&quot;&lt;/p&gt;
&lt;p&gt;Remember to review these words and the grammar point several times throughout the day to help you remember them.&lt;/p&gt;
&lt;p&gt;Best,
Judy&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.clozemaster.com/blog/vocabulary-or-grammar/&quot;&gt;https://www.clozemaster.com/blog/vocabulary-or-grammar/&lt;/a&gt;
[2] &lt;a href=&quot;https://learnenglishkids.britishcouncil.org/grammar-vocabulary&quot;&gt;https://learnenglishkids.britishcouncil.org/grammar-vocabulary&lt;/a&gt;
[3] &lt;a href=&quot;https://www.reading.ac.uk/global-study-lounge/eap/vocabulary-grammar&quot;&gt;https://www.reading.ac.uk/global-study-lounge/eap/vocabulary-grammar&lt;/a&gt;
[4] &lt;a href=&quot;https://languageartsclassroom.com/vocabulary-and-grammar-lesson-10-words/&quot;&gt;https://languageartsclassroom.com/vocabulary-and-grammar-lesson-10-words/&lt;/a&gt;
[5] &lt;a href=&quot;https://www.strawblondiestudies.co.uk/post/7-actionable-tips-to-learn-new-vocabulary-in-your-target-language&quot;&gt;https://www.strawblondiestudies.co.uk/post/7-actionable-tips-to-learn-new-vocabulary-in-your-target-language&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 37 of learning English</title><link>https://blog.ithuo.net/posts/day-37-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-37-of-learning-english/</guid><pubDate>Sat, 06 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dear Derick,&lt;/p&gt;
&lt;p&gt;On the fourth day of Week 6, here are some effective ways to learn vocabulary and grammar:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vocabulary Learning&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Word Wall&lt;/strong&gt;: Create a word wall with the new words you&apos;ve learned. This is a collection of words displayed in large visible letters on a wall or bulletin board. It helps raise your awareness of and interest in words and their meanings[3].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Written Repetition&lt;/strong&gt;: Write each new word 10-15 times. This helps you remember the spelling and pronunciation of the words. Saying the words out loud as you write them can also help commit them to memory[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vocabulary Games&lt;/strong&gt;: Play vocabulary games to review the words you&apos;ve learned. Games make learning fun and engaging, which can help you remember the words better[1].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Grammar Learning&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Grammar Exercises&lt;/strong&gt;: Continue practicing the past perfect and future perfect tenses through exercises. This could include fill-in-the-blank activities or sentence transformation exercises[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practical Application&lt;/strong&gt;: Use the grammar points in speaking or writing. For example, describe past experiences using the past perfect tense and narrate future events using the future perfect tense[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review&lt;/strong&gt;: Review the grammar rules and structures you&apos;ve learned. Revisit your notes and practice sentences to reinforce your understanding[5].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember, the key to effective learning is consistency and practice. Review the vocabulary words and grammar points several times throughout the day to help you remember them[1][5].&lt;/p&gt;
&lt;p&gt;On the fourth day of Week 6, you should continue to build on the vocabulary and grammar you have been learning. Here are the new words and grammar points to focus on:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vocabulary Learning&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Abstract&lt;/strong&gt;: existing in thought or as an idea but not having a physical or concrete existence.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Comprehensive&lt;/strong&gt;: complete; including all or nearly all elements or aspects of something.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Explicit&lt;/strong&gt;: stated clearly and in detail, leaving no room for confusion or doubt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implicit&lt;/strong&gt;: implied though not plainly expressed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inherent&lt;/strong&gt;: existing in something as a permanent, essential, or characteristic attribute.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Insight&lt;/strong&gt;: the capacity to gain an accurate and deep intuitive understanding of a person or thing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Predominant&lt;/strong&gt;: present as the strongest or main element.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rational&lt;/strong&gt;: based on or in accordance with reason or logic.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Empirical&lt;/strong&gt;: based on, concerned with, or verifiable by observation or experience rather than theory or pure logic.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hypothesis&lt;/strong&gt;: a supposition or proposed explanation made on the basis of limited evidence as a starting point for further investigation.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Grammar Learning&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Past Perfect Tense&lt;/strong&gt;: Continue practicing the past perfect tense, which is used to describe actions that were completed before another action in the past. For example, &quot;I had finished my homework before dinner.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Future Perfect Tense&lt;/strong&gt;: Introduce and practice the future perfect tense, which is used to describe actions that will be completed before a specific time in the future. For example, &quot;By next year, I will have graduated from university.&quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Use these vocabulary words in sentences to practice their usage and incorporate the grammar points into your writing and speaking exercises. Review the meanings, spellings, and applications of these words and tenses regularly to reinforce your learning.&lt;/p&gt;
&lt;p&gt;Remember, it&apos;s important to use the words and grammar in context, as this helps to solidify your understanding and ability to use them naturally in conversation[1][2][3][4][5].&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://notsowimpyteacher.com/2022/07/how-to-launch-a-vocabulary-routine-in-10-minutes-a-day.html&quot;&gt;https://notsowimpyteacher.com/2022/07/how-to-launch-a-vocabulary-routine-in-10-minutes-a-day.html&lt;/a&gt;
[2] &lt;a href=&quot;https://www.responsiveclassroom.org/the-first-six-weeks-of-school/&quot;&gt;https://www.responsiveclassroom.org/the-first-six-weeks-of-school/&lt;/a&gt;
[3] &lt;a href=&quot;https://edulearn2change.com/article-strategies-for-teaching-vocabulary/&quot;&gt;https://edulearn2change.com/article-strategies-for-teaching-vocabulary/&lt;/a&gt;
[4] &lt;a href=&quot;https://www.strawblondiestudies.co.uk/post/7-actionable-tips-to-learn-new-vocabulary-in-your-target-language&quot;&gt;https://www.strawblondiestudies.co.uk/post/7-actionable-tips-to-learn-new-vocabulary-in-your-target-language&lt;/a&gt;
[5] &lt;a href=&quot;https://www.reading.ac.uk/global-study-lounge/eap/vocabulary-grammar&quot;&gt;https://www.reading.ac.uk/global-study-lounge/eap/vocabulary-grammar&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 36 of learning English</title><link>https://blog.ithuo.net/posts/day-36-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-36-of-learning-english/</guid><pubDate>Fri, 05 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dear Derick,&lt;/p&gt;
&lt;p&gt;On the third day of Week 6, to effectively learn vocabulary and grammar, you should incorporate the following strategies:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vocabulary Learning&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Contextual Learning&lt;/strong&gt;: Put the new words you&apos;ve learned into context. This could involve reading a passage, watching a video, or listening to a conversation where these words are used[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Non-Linguistic Representation&lt;/strong&gt;: Create non-linguistic representations for the words you&apos;ve learned. This could be through drawings, symbols, or even acting out the words to reinforce their meanings[2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Think-Pair-Shares&lt;/strong&gt;: Discuss the meanings of the words with a partner or in a study group. This allows for peer learning and can help clarify any misunderstandings about word usage[2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sentence Writing&lt;/strong&gt;: Write sentences using the new vocabulary. This helps you practice grammar and understand how the words fit into the structure of a sentence[2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review and Self-Assessment&lt;/strong&gt;: Review the words you&apos;ve learned and assess your understanding. You can use self-assessment scales to gauge your comfort level with each word[2].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Grammar Learning&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Grammar Exercises&lt;/strong&gt;: Continue practicing the present perfect and past perfect tenses through exercises. This could include fill-in-the-blank activities or sentence transformation exercises[3].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practical Application&lt;/strong&gt;: Use the grammar points in speaking or writing. For example, describe past experiences using the present perfect tense and narrate past events using the past perfect tense[3].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review&lt;/strong&gt;: Review the grammar rules and structures you&apos;ve learned. Revisit your notes and practice sentences to reinforce your understanding[3].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By combining these strategies, you will reinforce the vocabulary and grammar you&apos;ve learned, making it easier to remember and use them correctly in conversation.&lt;/p&gt;
&lt;p&gt;On the third day of Week 6, here are the new words and grammar points you should focus on:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vocabulary Learning&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Based on the vocabulary list provided in the search results[5], here are 20 new words you should learn:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Abstract&lt;/li&gt;
&lt;li&gt;Comprehensive&lt;/li&gt;
&lt;li&gt;Explicit&lt;/li&gt;
&lt;li&gt;Implicit&lt;/li&gt;
&lt;li&gt;Inherent&lt;/li&gt;
&lt;li&gt;Insight&lt;/li&gt;
&lt;li&gt;Predominant&lt;/li&gt;
&lt;li&gt;Rational&lt;/li&gt;
&lt;li&gt;Empirical&lt;/li&gt;
&lt;li&gt;Hypothesis&lt;/li&gt;
&lt;li&gt;Analogy&lt;/li&gt;
&lt;li&gt;Anomaly&lt;/li&gt;
&lt;li&gt;Anticipate&lt;/li&gt;
&lt;li&gt;Complement&lt;/li&gt;
&lt;li&gt;Contradict&lt;/li&gt;
&lt;li&gt;Denote&lt;/li&gt;
&lt;li&gt;Diminish&lt;/li&gt;
&lt;li&gt;Evoke&lt;/li&gt;
&lt;li&gt;Fluctuate&lt;/li&gt;
&lt;li&gt;Inhibit&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For each word, understand its meaning, pronunciation, and usage in a sentence. You can use the context clues provided in the sentences from the vocabulary list[5] to understand how each word is used.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Grammar Learning&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;On the third day, continue with the past perfect tense. This tense is used to describe an action that occurred and was completed in the past before another past action[2][3]. Practice constructing sentences using this tense, such as &quot;I had studied English before I met Judy.&quot;&lt;/p&gt;
&lt;p&gt;Also, introduce the future perfect tense. This tense is used to describe an action that will have been completed at some point in the future[2][3]. Practice constructing sentences using this tense, such as &quot;I will have learned 60 new words by the end of this week.&quot;&lt;/p&gt;
&lt;p&gt;Remember to review these words and the grammar point several times throughout the day to help you remember them.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.clozemaster.com/blog/vocabulary-or-grammar/&quot;&gt;https://www.clozemaster.com/blog/vocabulary-or-grammar/&lt;/a&gt;
[2] &lt;a href=&quot;https://www.reading.ac.uk/global-study-lounge/eap/vocabulary-grammar&quot;&gt;https://www.reading.ac.uk/global-study-lounge/eap/vocabulary-grammar&lt;/a&gt;
[3] &lt;a href=&quot;https://learnenglishkids.britishcouncil.org/grammar-vocabulary&quot;&gt;https://learnenglishkids.britishcouncil.org/grammar-vocabulary&lt;/a&gt;
[4] &lt;a href=&quot;https://www.britishcouncil.org/voices-magazine/ten-ways-learn-new-words-language-learner&quot;&gt;https://www.britishcouncil.org/voices-magazine/ten-ways-learn-new-words-language-learner&lt;/a&gt;
[5] &lt;a href=&quot;https://languageartsclassroom.com/vocabulary-and-grammar-lesson-10-words/&quot;&gt;https://languageartsclassroom.com/vocabulary-and-grammar-lesson-10-words/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 35 of learning English</title><link>https://blog.ithuo.net/posts/day-35-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-35-of-learning-english/</guid><pubDate>Thu, 04 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dear Derick,&lt;/p&gt;
&lt;p&gt;On the second day of Week 6, here are some effective ways to learn vocabulary and grammar:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vocabulary Learning&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Non-Linguistic Representation&lt;/strong&gt;: Create a non-linguistic representation of the words you learned on the first day. This could be a drawing, a symbol, or a physical gesture that helps you remember the meaning of the word[2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Spaced Repetition&lt;/strong&gt;: Use spaced repetition to review the words. This method involves reviewing the words at increasing intervals over time. This is a proven method to help fix new words in your memory[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use in Context&lt;/strong&gt;: Try to use the new words in context. This could be in a sentence or a conversation. Using the words in context helps you understand how they are used and makes them easier to remember[1][5].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Grammar Learning&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Grammar Exercises&lt;/strong&gt;: Continue practicing the present perfect tense by doing more exercises. This could be filling in the blanks, rewriting sentences, or correcting mistakes in sentences[3].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use in Context&lt;/strong&gt;: Just like vocabulary, try to use the grammar point in context. This could be in a sentence or a conversation. Using the grammar point in context helps you understand how it is used and makes it easier to remember[3].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review&lt;/strong&gt;: Review the grammar point several times throughout the day. This can be done by writing sentences using the grammar point and saying them out loud[3].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember, the key to effective learning is consistency and practice. Review the vocabulary words and grammar points several times throughout the day to help you remember them[1][3].&lt;/p&gt;
&lt;p&gt;On the second day of Week 6, here are the new words and grammar points you should focus on:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vocabulary Learning&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Based on the vocabulary list provided in the search results[5], here are 20 new words you should learn:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Ambiguous&lt;/li&gt;
&lt;li&gt;Consensus&lt;/li&gt;
&lt;li&gt;Discrepancy&lt;/li&gt;
&lt;li&gt;Fluctuate&lt;/li&gt;
&lt;li&gt;Inhibit&lt;/li&gt;
&lt;li&gt;Predominant&lt;/li&gt;
&lt;li&gt;Subsequent&lt;/li&gt;
&lt;li&gt;Accumulate&lt;/li&gt;
&lt;li&gt;Constrain&lt;/li&gt;
&lt;li&gt;Diminish&lt;/li&gt;
&lt;li&gt;Emerge&lt;/li&gt;
&lt;li&gt;Inevitable&lt;/li&gt;
&lt;li&gt;Preliminary&lt;/li&gt;
&lt;li&gt;Summarize&lt;/li&gt;
&lt;li&gt;Adjacent&lt;/li&gt;
&lt;li&gt;Commodity&lt;/li&gt;
&lt;li&gt;Discrete&lt;/li&gt;
&lt;li&gt;Exclude&lt;/li&gt;
&lt;li&gt;Inherent&lt;/li&gt;
&lt;li&gt;Prospect&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For each word, understand its meaning, pronunciation, and usage in a sentence. You can use the context clues provided in the sentences from the vocabulary list[5] to understand how each word is used.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Grammar Learning&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;On the second day, continue with the present perfect tense, but also introduce the past perfect tense. The past perfect tense is used to describe an action that occurred and was completed in the past before another past action[2][3]. Practice constructing sentences using this tense, such as &quot;I had studied English before I met Judy.&quot;&lt;/p&gt;
&lt;p&gt;Remember to review these words and the grammar point several times throughout the day to help you remember them.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.britishcouncil.org/voices-magazine/ten-ways-learn-new-words-language-learner&quot;&gt;https://www.britishcouncil.org/voices-magazine/ten-ways-learn-new-words-language-learner&lt;/a&gt;
[2] &lt;a href=&quot;https://tefl-tesol-certification.com/blog/first-day-of-classes-for-adult-esl-students&quot;&gt;https://tefl-tesol-certification.com/blog/first-day-of-classes-for-adult-esl-students&lt;/a&gt;
[3] &lt;a href=&quot;https://omproofreading.com/grammar-vs-vocabulary/&quot;&gt;https://omproofreading.com/grammar-vs-vocabulary/&lt;/a&gt;
[4] &lt;a href=&quot;https://notsowimpyteacher.com/2022/07/how-to-launch-a-vocabulary-routine-in-10-minutes-a-day.html&quot;&gt;https://notsowimpyteacher.com/2022/07/how-to-launch-a-vocabulary-routine-in-10-minutes-a-day.html&lt;/a&gt;
[5] &lt;a href=&quot;https://coe.unt.edu/sites/default/files/components_of_lang_and_reading_instruction.pdf&quot;&gt;https://coe.unt.edu/sites/default/files/components_of_lang_and_reading_instruction.pdf&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 34 of learning English</title><link>https://blog.ithuo.net/posts/day-34-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-34-of-learning-english/</guid><pubDate>Wed, 03 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the first day of Week 6, here are some effective ways to learn vocabulary and grammar:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vocabulary Learning&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Introduce New Words&lt;/strong&gt;: Start by introducing new words. You can do this by giving a sentence with the new vocabulary word and asking yourself to guess what the word means. Use context clues and make inferences to arrive at possible meanings[1].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consistent Routine&lt;/strong&gt;: Follow a consistent vocabulary routine. This helps you know what to expect and saves time because you only have to learn the directions once[1].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use Vocabulary Games&lt;/strong&gt;: Games are a fun and effective way to learn new words. They engage you in the learning process, making it easier for you to remember the words. Some games you can try include Trashketball, Pop, and Charades[1].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Grammar Learning&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Understanding the Structure&lt;/strong&gt;: Spend time understanding the structure of the grammar point you&apos;re learning. For example, if you&apos;re learning the present perfect tense, understand how it&apos;s formed and when it&apos;s used[3].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practical Application&lt;/strong&gt;: Apply the grammar point in real-life contexts. This could be through writing sentences or speaking. This helps you understand the practical use of the grammar point[3].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grammar Games&lt;/strong&gt;: Just like vocabulary, games can also be effective in learning grammar. They make the learning process fun and engaging, helping you understand and remember the grammar point better[3].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember, the key to effective learning is consistency and practice. Review the vocabulary words and grammar points several times throughout the day to help you remember them[1][3].&lt;/p&gt;
&lt;h3&gt;Vocabulary&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Affluent&lt;/li&gt;
&lt;li&gt;Feasible&lt;/li&gt;
&lt;li&gt;Deteriorate&lt;/li&gt;
&lt;li&gt;Substantial&lt;/li&gt;
&lt;li&gt;Conventional&lt;/li&gt;
&lt;li&gt;Integral&lt;/li&gt;
&lt;li&gt;Compensate&lt;/li&gt;
&lt;li&gt;Reinforce&lt;/li&gt;
&lt;li&gt;Undermine&lt;/li&gt;
&lt;li&gt;Inevitable&lt;/li&gt;
&lt;li&gt;Uniform&lt;/li&gt;
&lt;li&gt;Complement&lt;/li&gt;
&lt;li&gt;Adequate&lt;/li&gt;
&lt;li&gt;Virtual&lt;/li&gt;
&lt;li&gt;Coherent&lt;/li&gt;
&lt;li&gt;Restrain&lt;/li&gt;
&lt;li&gt;Inherent&lt;/li&gt;
&lt;li&gt;Protocol&lt;/li&gt;
&lt;li&gt;Empirical&lt;/li&gt;
&lt;li&gt;Levy&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For each word, understand its meaning, pronunciation, and usage in a sentence. You can use the context clues provided in the sentences from the vocabulary list[5] to understand how each word is used.&lt;/p&gt;
&lt;p&gt;For grammar, as mentioned earlier, focus on the present perfect tense. This tense is used to describe actions that have happened at an unspecified time before now or actions that started in the past and continue to the present[4]. Practice constructing sentences using this tense.&lt;/p&gt;
&lt;p&gt;Remember to review these words and the grammar point several times throughout the day to help you remember them.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://notsowimpyteacher.com/2022/07/how-to-launch-a-vocabulary-routine-in-10-minutes-a-day.html&quot;&gt;https://notsowimpyteacher.com/2022/07/how-to-launch-a-vocabulary-routine-in-10-minutes-a-day.html&lt;/a&gt;
[2] &lt;a href=&quot;https://www.responsiveclassroom.org/the-first-six-weeks-of-school/&quot;&gt;https://www.responsiveclassroom.org/the-first-six-weeks-of-school/&lt;/a&gt;
[3] &lt;a href=&quot;https://tefl-tesol-certification.com/blog/first-day-of-classes-for-adult-esl-students&quot;&gt;https://tefl-tesol-certification.com/blog/first-day-of-classes-for-adult-esl-students&lt;/a&gt;
[4] &lt;a href=&quot;https://resources.depaul.edu/teaching-commons/teaching-guides/learning-activities/Pages/the-first-day.aspx&quot;&gt;https://resources.depaul.edu/teaching-commons/teaching-guides/learning-activities/Pages/the-first-day.aspx&lt;/a&gt;
[5] &lt;a href=&quot;https://www.teach-this.com/ideas/the-first-day-of-class&quot;&gt;https://www.teach-this.com/ideas/the-first-day-of-class&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 33 of learning English</title><link>https://blog.ithuo.net/posts/day-33-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-33-of-learning-english/</guid><pubDate>Tue, 02 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For the seventh day of the fifth week, it&apos;s important to take a step back and reflect on the progress made so far. This day can be used for rest, review, and reinforcement of the concepts learned throughout the week.&lt;/p&gt;
&lt;h2&gt;Sunday - Week 5&lt;/h2&gt;
&lt;h3&gt;Morning Session: Reflection and Self-Assessment&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Reflect on the progress made this week and assess areas that need more practice.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Review your notes and self-assess your understanding of the vocabulary and grammar points learned.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Identify areas where you feel confident and areas that require more practice.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Midday Session: Vocabulary and Grammar Review&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Solidify your grasp of the week&apos;s vocabulary and grammar.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Revisit the vocabulary and grammar exercises from the week, focusing on any challenging areas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Gain a deeper understanding of the material and improve your ability to use it in context.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Afternoon Session: Relaxation and Immersion&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Immerse yourself in the English language in a relaxed setting.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Watch an English-language movie or TV show, listen to English music, or read an English book for pleasure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Enhance language skills through passive learning and enjoy the process of language acquisition.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Evening Session: Casual Conversation Practice&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Practice speaking English in a casual, stress-free environment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Have an informal conversation with me or another English speaker about how you feel today or any topic of your choice.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Build confidence in speaking English and practice using the language in a natural setting.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification of Study Results&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Method&lt;/strong&gt;: We will have a casual conversation to review the week&apos;s learning. I will provide feedback on your overall progress and suggest areas for continued focus.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This day&apos;s plan is designed to be less structured, allowing for rest and consolidation of the week&apos;s learning. It&apos;s also a chance to enjoy the language in a more natural context, which can be highly beneficial for language retention and motivation[1][2][3][4][5].&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://weibo.com/1777467311/N8IR9orep&quot;&gt;https://weibo.com/1777467311/N8IR9orep&lt;/a&gt;
[2] &lt;a href=&quot;http://www.judyyoga.com/blog/?p=1149&quot;&gt;http://www.judyyoga.com/blog/?p=1149&lt;/a&gt;
[3] &lt;a href=&quot;https://www.tenexpress.com/3989.html&quot;&gt;https://www.tenexpress.com/3989.html&lt;/a&gt;
[4] &lt;a href=&quot;http://www.judyyoga.com/blog/?p=301&quot;&gt;http://www.judyyoga.com/blog/?p=301&lt;/a&gt;
[5] &lt;a href=&quot;http://www.judyyoga.com/blog/?p=2169&quot;&gt;http://www.judyyoga.com/blog/?p=2169&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 32 of learning English</title><link>https://blog.ithuo.net/posts/day-32-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-32-of-learning-english/</guid><pubDate>Mon, 01 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For the sixth day of the fifth week, we will focus on enhancing your listening skills and reviewing the content learned throughout the week.&lt;/p&gt;
&lt;h2&gt;Saturday - Week 5&lt;/h2&gt;
&lt;h3&gt;Morning Session: Listening Practice&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Improve your listening comprehension skills.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Listen to English podcasts or watch English videos on topics of your interest. Try to understand the content without using subtitles. Write down any new words or phrases you hear.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Be able to understand spoken English better and expand your vocabulary.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Midday Session: Vocabulary and Grammar Review&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Review the vocabulary and grammar learned this week.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Use flashcards to review the vocabulary. Practice forming sentences using the grammar points learned this week (past simple, past continuous, future simple, future continuous tenses, and modal verbs).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Reinforce the vocabulary and grammar learned this week.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Afternoon Session: Reading Comprehension&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Practice reading comprehension with a focus on new vocabulary and grammar.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Read a short article or story and identify the new vocabulary and instances of the grammar points learned this week.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Summarize the article and discuss the use of the grammar points.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Evening Session: Speaking Practice&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Apply the learned vocabulary and grammar in speaking contexts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Have a conversation with me or another English speaker, trying to use the new vocabulary and grammar points.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Improve your speaking skills and gain confidence in using English in conversation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification of Study Results&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Method&lt;/strong&gt;: We will have a conversation where you will use the vocabulary and grammar learned throughout the week. I will assess your ability to use the grammar points and provide feedback on your conversational skills.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This day&apos;s plan is designed to consolidate your learning from the week and to practice applying it in a way that mimics real-world use, preparing you for more natural and spontaneous English communication[1][2][3][4].&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.zhihu.com/question/24962836/answer/193177771&quot;&gt;https://www.zhihu.com/question/24962836/answer/193177771&lt;/a&gt;
[2] &lt;a href=&quot;https://weibo.com/1777467311/N8IR9orep&quot;&gt;https://weibo.com/1777467311/N8IR9orep&lt;/a&gt;
[3] &lt;a href=&quot;https://www.tenexpress.com/3989.html&quot;&gt;https://www.tenexpress.com/3989.html&lt;/a&gt;
[4] &lt;a href=&quot;http://www.judyyoga.com/blog/?p=301&quot;&gt;http://www.judyyoga.com/blog/?p=301&lt;/a&gt;
[5] &lt;a href=&quot;http://www.judyyoga.com/blog/?p=2169&quot;&gt;http://www.judyyoga.com/blog/?p=2169&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 31 of learning English</title><link>https://blog.ithuo.net/posts/day-31-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-31-of-learning-english/</guid><pubDate>Sun, 31 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For the fifth day of the fifth week, let&apos;s focus on integrating the vocabulary and grammar you&apos;ve learned so far with practical application exercises to enhance your conversational skills.&lt;/p&gt;
&lt;h2&gt;Friday - Week 5&lt;/h2&gt;
&lt;h3&gt;Morning Session: Review and Vocabulary Integration&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Review the vocabulary learned this week and integrate it into full sentences.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Create flashcards with the vocabulary from the previous days and practice making complex sentences with them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Be able to use the vocabulary in context, forming sentences that could be used in real-life situations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Midday Session: Grammar Focus - Modal Verbs&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Understand and practice using modal verbs for expressing possibility, ability, permission, and obligation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grammar Point&lt;/strong&gt;: Modal Verbs. For example, &quot;can/could&quot;, &quot;may/might&quot;, &quot;must&quot;, &quot;should&quot;, &quot;will/would&quot;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Complete exercises from an English grammar workbook or online resource, focusing on modal verbs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Be able to use modal verbs correctly in sentences to express different nuances.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Afternoon Session: Practical Application - Role Play&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Apply vocabulary and grammar in simulated real-life scenarios.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Engage in role-play exercises where you simulate situations like a job interview, making a reservation, or asking for directions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Be able to communicate effectively in various scenarios using the vocabulary and grammar learned.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Evening Session: Listening and Speaking Practice&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Enhance listening comprehension and speaking fluency.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Watch the YouTube video &quot;English Conversations for Daily Life&quot; and practice along with the conversations[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Be able to understand and participate in basic English conversations about daily life.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification of Study Results&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Method&lt;/strong&gt;: We will have a conversation where you will use the vocabulary and grammar learned throughout the week. I will assess your ability to use modal verbs and provide feedback on your conversational skills.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This day&apos;s plan is designed to consolidate your learning from the week and to practice applying it in a way that mimics real-world use, preparing you for more natural and spontaneous English communication[1][2][3][4].&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.zhihu.com/question/35103080/answer/810489721&quot;&gt;https://www.zhihu.com/question/35103080/answer/810489721&lt;/a&gt;
[2] &lt;a href=&quot;https://www.tenexpress.com/3989.html&quot;&gt;https://www.tenexpress.com/3989.html&lt;/a&gt;
[3] &lt;a href=&quot;http://www.judyyoga.com/blog/?p=301&quot;&gt;http://www.judyyoga.com/blog/?p=301&lt;/a&gt;
[4] &lt;a href=&quot;https://www.youtube.com/watch?v=h_KUklZdq5w&quot;&gt;https://www.youtube.com/watch?v=h_KUklZdq5w&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 30 of learning English</title><link>https://blog.ithuo.net/posts/day-30-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-30-of-learning-english/</guid><pubDate>Sat, 30 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For the third day of the fifth week, we will continue to build on your vocabulary and grammar skills, incorporating new words and grammatical structures to enhance your English proficiency.&lt;/p&gt;
&lt;h2&gt;Wednesday - Week 5&lt;/h2&gt;
&lt;h3&gt;Morning Session: Vocabulary Expansion&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Learn new academic vocabulary words that are commonly used across various subjects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Words&lt;/strong&gt;:
&lt;ol&gt;
&lt;li&gt;Abolish&lt;/li&gt;
&lt;li&gt;Escalate&lt;/li&gt;
&lt;li&gt;Influence&lt;/li&gt;
&lt;li&gt;Accomplish&lt;/li&gt;
&lt;li&gt;Establish&lt;/li&gt;
&lt;li&gt;Investigate&lt;/li&gt;
&lt;li&gt;Accurate&lt;/li&gt;
&lt;li&gt;Evaluate&lt;/li&gt;
&lt;li&gt;Navigate&lt;/li&gt;
&lt;li&gt;Announce&lt;/li&gt;
&lt;li&gt;Evidence&lt;/li&gt;
&lt;li&gt;Opposed&lt;/li&gt;
&lt;li&gt;Anxious&lt;/li&gt;
&lt;li&gt;Exhaust&lt;/li&gt;
&lt;li&gt;Ordinary&lt;/li&gt;
&lt;li&gt;Approach&lt;/li&gt;
&lt;li&gt;Expansion&lt;/li&gt;
&lt;li&gt;Passage&lt;/li&gt;
&lt;li&gt;Approval&lt;/li&gt;
&lt;li&gt;Expectation&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Midday Session: Grammar Focus - Future Simple Tense&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Learn to express future intentions and predictions using the future simple tense.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grammar Point&lt;/strong&gt;: Future Simple Tense. For example, &quot;I will travel&quot;, &quot;She will study&quot;, &quot;They will eat&quot;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Practice forming sentences using the future simple tense with the new vocabulary words.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Be able to discuss future plans or predictions using the correct tense.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Afternoon Session: Reading Comprehension&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Practice reading comprehension with a focus on new vocabulary.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Read a short article or story and identify the new vocabulary and instances of future simple tense.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Summarize the article and discuss the use of the tense.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Evening Session: Listening and Speaking Practice&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Apply the learned vocabulary and grammar in listening and speaking contexts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Listen to a podcast or watch a video that includes dialogues using the future simple tense. Try to identify the new vocabulary within the context.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Have a conversation with me using the new vocabulary and grammar points.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification of Study Results&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Method&lt;/strong&gt;: We will have a conversation where you will use the new vocabulary words in context and demonstrate your understanding of the future simple tense. I will provide feedback on your pronunciation, grammar, and comprehension.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This plan aims to integrate new vocabulary with grammatical structures, allowing you to practice and apply what you&apos;ve learned in a variety of contexts[4].&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.youtube.com/watch?v=957doLM7BXc&quot;&gt;https://www.youtube.com/watch?v=957doLM7BXc&lt;/a&gt;
[2] &lt;a href=&quot;https://www.youtube.com/watch?v=3JiqDcD8UmQ&quot;&gt;https://www.youtube.com/watch?v=3JiqDcD8UmQ&lt;/a&gt;
[3] &lt;a href=&quot;https://www.education.com/lesson-plans/fifth-grade/&quot;&gt;https://www.education.com/lesson-plans/fifth-grade/&lt;/a&gt;
[4] &lt;a href=&quot;https://www.greatschools.org/gk/articles/academic-vocabulary-words-for-fifth-graders/&quot;&gt;https://www.greatschools.org/gk/articles/academic-vocabulary-words-for-fifth-graders/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 29 of learning English</title><link>https://blog.ithuo.net/posts/day-29-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-29-of-learning-english/</guid><pubDate>Fri, 29 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Sure, Derick. Here&apos;s your learning plan for the second day of the fifth week:&lt;/p&gt;
&lt;h2&gt;Tuesday - Week 5&lt;/h2&gt;
&lt;h3&gt;Morning Session: Vocabulary Expansion&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Learn 20 new vocabulary words related to software technology.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Words&lt;/strong&gt;: Algorithm, Binary, Compile, Debug, Encrypt, Firewall, Gateway, Hardware, Interface, Kernel, Loop, Malware, Node, Object, Protocol, Query, Server, Thread, Virtual, Widget.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Use Quizlet or a similar app to study and memorize the words. Practice using them in sentences.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Be able to spell, pronounce, and use each word in a sentence.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Midday Session: Grammar Focus - Past Continuous Tense&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Understand and practice the past continuous tense.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grammar Point&lt;/strong&gt;: Past Continuous Tense. For example, &quot;I was working&quot;, &quot;They were cooking&quot;, &quot;We were going&quot;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Complete exercises from an English grammar workbook or online resource. Practice converting past simple tense sentences to past continuous tense.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Correctly form past continuous tense sentences and convert past simple tense sentences to past continuous tense.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Afternoon Session: Reading Comprehension&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Improve reading skills and comprehension.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reading Material&lt;/strong&gt;: A short article related to software technology from a reputable source.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Read the article and summarize its main points. Write down any new vocabulary and look up their meanings.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Be able to discuss the content of the article and answer comprehension questions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Evening Session: Listening and Speaking Practice&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Enhance listening skills and practice speaking.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Listening Material&lt;/strong&gt;: An English-language video about software technology.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Watch the video, take notes, and prepare to discuss it. Practice using the new vocabulary and past continuous tense.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Discuss the video with me, focusing on using the new vocabulary and past continuous tense.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification of Study Results&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Method&lt;/strong&gt;: We will have a conversation where you will use the new vocabulary words in context and demonstrate your understanding of the past continuous tense. I will provide feedback on your pronunciation, grammar, and comprehension.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember to take breaks between sessions to rest and process the information. Consistency and practice are crucial, so stick to the plan and reach out if you encounter any difficulties[2][3][4].&lt;/p&gt;
&lt;p&gt;Based on the guidance from the search results, it&apos;s clear that vocabulary is a fundamental building block in language learning and should be prioritized, especially in the early stages. However, grammar is also essential for constructing correct sentences and should not be neglected. Therefore, for the second day of the fifth week, we will focus on both vocabulary and grammar.&lt;/p&gt;
&lt;h2&gt;Tuesday - Week 5&lt;/h2&gt;
&lt;h3&gt;Morning Session: Vocabulary Expansion&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Learn new vocabulary words related to common daily activities and interactions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Words&lt;/strong&gt;:
&lt;ol&gt;
&lt;li&gt;Schedule&lt;/li&gt;
&lt;li&gt;Appointment&lt;/li&gt;
&lt;li&gt;Deadline&lt;/li&gt;
&lt;li&gt;Leisure&lt;/li&gt;
&lt;li&gt;Errand&lt;/li&gt;
&lt;li&gt;Invoice&lt;/li&gt;
&lt;li&gt;Receipt&lt;/li&gt;
&lt;li&gt;Refund&lt;/li&gt;
&lt;li&gt;Discount&lt;/li&gt;
&lt;li&gt;Warranty&lt;/li&gt;
&lt;li&gt;Exchange&lt;/li&gt;
&lt;li&gt;Delivery&lt;/li&gt;
&lt;li&gt;Reservation&lt;/li&gt;
&lt;li&gt;Cancellation&lt;/li&gt;
&lt;li&gt;Inquiry&lt;/li&gt;
&lt;li&gt;Assistance&lt;/li&gt;
&lt;li&gt;Feedback&lt;/li&gt;
&lt;li&gt;Recommendation&lt;/li&gt;
&lt;li&gt;Complaint&lt;/li&gt;
&lt;li&gt;Service&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Midday Session: Grammar Focus - Past Simple vs. Past Continuous&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Understand the difference between past simple and past continuous tense and when to use each.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grammar Points&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;Past Simple Tense: Used for completed actions in the past (e.g., &quot;I finished the report yesterday.&quot;)&lt;/li&gt;
&lt;li&gt;Past Continuous Tense: Used for actions that were in progress at a specific time in the past (e.g., &quot;I was working on the report at 8 PM yesterday.&quot;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Complete exercises from an English grammar workbook or online resource, focusing on these two tenses.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Be able to distinguish between the two tenses and use them correctly in sentences.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Afternoon Session: Reading Comprehension&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Practice reading comprehension with a focus on new vocabulary and grammar.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Read a short article or story and identify the new vocabulary and instances of past simple and past continuous tenses.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Summarize the article and discuss the use of the tenses.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Evening Session: Listening and Speaking Practice&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Apply the learned vocabulary and grammar in listening and speaking contexts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Listen to a podcast or watch a video that includes dialogues using the past simple and past continuous tenses. Try to identify the new vocabulary within the context.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Have a conversation with me using the new vocabulary and grammar points.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification of Study Results&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Method&lt;/strong&gt;: We will have a conversation where you will use the new vocabulary words in context and demonstrate your understanding of the past simple and past continuous tenses. I will provide feedback on your pronunciation, grammar, and comprehension.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This balanced approach should help you build a strong foundation in both vocabulary and grammar, which are both crucial for effective communication in English[1][2][3][4].&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.youtube.com/watch?v=3JiqDcD8UmQ&quot;&gt;https://www.youtube.com/watch?v=3JiqDcD8UmQ&lt;/a&gt;
[2] &lt;a href=&quot;https://www.greatschools.org/gk/articles/academic-vocabulary-words-for-fifth-graders/&quot;&gt;https://www.greatschools.org/gk/articles/academic-vocabulary-words-for-fifth-graders/&lt;/a&gt;
[3] &lt;a href=&quot;https://most.oercommons.org/courseware/lesson/455/student/&quot;&gt;https://most.oercommons.org/courseware/lesson/455/student/&lt;/a&gt;
[4] &lt;a href=&quot;https://www.indeed.com/career-advice/career-development/lesson-plan-example&quot;&gt;https://www.indeed.com/career-advice/career-development/lesson-plan-example&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 28 of learning English</title><link>https://blog.ithuo.net/posts/day-28-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-28-of-learning-english/</guid><pubDate>Thu, 28 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Sure, Derick. Here&apos;s a more detailed plan for the first day of the fifth week:&lt;/p&gt;
&lt;h2&gt;Monday - Week 5&lt;/h2&gt;
&lt;h3&gt;Morning Session: Vocabulary Expansion&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Learn 20 new vocabulary words related to everyday activities.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Words&lt;/strong&gt;: Routine, breakfast, exercise, commute, work, lunch, meeting, dinner, relax, sleep, hobby, weekend, chores, leisure, outing, shopping, cooking, cleaning, laundry, gardening.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Use Quizlet or a similar app to study and memorize the words. Practice using them in sentences.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Be able to spell, pronounce, and use each word in a sentence.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Midday Session: Grammar Focus - Past Simple Tense&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Understand and practice the past simple tense for regular and irregular verbs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grammar Point&lt;/strong&gt;: Past Simple Tense. For example, &quot;I worked&quot;, &quot;They cooked&quot;, &quot;We went&quot;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Complete exercises from an English grammar workbook or online resource. Practice converting present tense sentences to past tense.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Correctly form past simple tense sentences and convert present tense sentences to past tense.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Afternoon Session: Reading Comprehension&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Improve reading skills and comprehension.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reading Material&lt;/strong&gt;: A short article related to technology from a reputable source.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Read the article and summarize its main points. Write down any new vocabulary and look up their meanings.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Be able to discuss the content of the article and answer comprehension questions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Evening Session: Listening and Speaking Practice&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Enhance listening skills and practice speaking.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Listening Material&lt;/strong&gt;: An English-language video about software technology.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity&lt;/strong&gt;: Watch the video, take notes, and prepare to discuss it. Practice using the new vocabulary and past simple tense.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outcome&lt;/strong&gt;: Discuss the video with me, focusing on using the new vocabulary and past simple tense.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification of Study Results&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Method&lt;/strong&gt;: We will have a conversation where you will use the new vocabulary words in context and demonstrate your understanding of the past simple tense. I will provide feedback on your pronunciation, grammar, and comprehension.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember to take breaks between sessions to rest and process the information. Consistency and practice are crucial, so stick to the plan and reach out if you encounter any difficulties.&lt;/p&gt;
&lt;p&gt;Sure, Derick. Here are 20 specific vocabulary words for you to learn today, based on the search results:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Accomplish&lt;/li&gt;
&lt;li&gt;Accurate&lt;/li&gt;
&lt;li&gt;Announce&lt;/li&gt;
&lt;li&gt;Anxious&lt;/li&gt;
&lt;li&gt;Approval&lt;/li&gt;
&lt;li&gt;Argument&lt;/li&gt;
&lt;li&gt;Avoid&lt;/li&gt;
&lt;li&gt;Briskly&lt;/li&gt;
&lt;li&gt;Cease&lt;/li&gt;
&lt;li&gt;Claim&lt;/li&gt;
&lt;li&gt;Conclude&lt;/li&gt;
&lt;li&gt;Conflict&lt;/li&gt;
&lt;li&gt;Consistent&lt;/li&gt;
&lt;li&gt;Context&lt;/li&gt;
&lt;li&gt;Convince&lt;/li&gt;
&lt;li&gt;Culture&lt;/li&gt;
&lt;li&gt;Decade&lt;/li&gt;
&lt;li&gt;Dissatisfied&lt;/li&gt;
&lt;li&gt;Dominate&lt;/li&gt;
&lt;li&gt;Drowsy&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each of these words is commonly used in English and will be useful in a variety of contexts. Try to use them in sentences to understand their meanings better. For example, &quot;I need to accomplish my tasks today&quot;, &quot;The report is accurate&quot;, &quot;I will announce the news&quot;, etc.&lt;/p&gt;
&lt;p&gt;Remember, understanding the meaning of a word is important, but knowing how to use it in context is what will truly help you improve your English skills.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://most.oercommons.org/courseware/lesson/455/student/&quot;&gt;https://most.oercommons.org/courseware/lesson/455/student/&lt;/a&gt;
[2] &lt;a href=&quot;https://www.teachstarter.com/us/blog/how-to-write-lesson-plan-printable-lesson-plan-template/&quot;&gt;https://www.teachstarter.com/us/blog/how-to-write-lesson-plan-printable-lesson-plan-template/&lt;/a&gt;
[3] &lt;a href=&quot;https://www.education.com/lesson-plans/fifth-grade/&quot;&gt;https://www.education.com/lesson-plans/fifth-grade/&lt;/a&gt;
[4] &lt;a href=&quot;https://www.weareteachers.com/lesson-plan-examples/&quot;&gt;https://www.weareteachers.com/lesson-plan-examples/&lt;/a&gt;
[5] &lt;a href=&quot;https://educationadvanced.com/resources/blog/weekly-lesson-plan-template-guidelines-you-should-know/&quot;&gt;https://educationadvanced.com/resources/blog/weekly-lesson-plan-template-guidelines-you-should-know/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 27 of learning English</title><link>https://blog.ithuo.net/posts/day-27-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-27-of-learning-english/</guid><pubDate>Wed, 27 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the seventh day of the fourth week, your learning tasks should focus on review and self-assessment. Here&apos;s a specific plan for the day:&lt;/p&gt;
&lt;h3&gt;Review&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Review all the vocabulary words you&apos;ve learned this week. Practice their pronunciation and usage in sentences.&lt;/li&gt;
&lt;li&gt;Review the grammar topics you&apos;ve focused on this week, particularly the present simple tense and the use of adverbs of frequency.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Self-Assessment&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Test yourself on the vocabulary words you&apos;ve learned. You can do this by creating flashcards with the word on one side and its meaning on the other, or by using a language learning app that includes vocabulary quizzes.&lt;/li&gt;
&lt;li&gt;Write sentences using the grammar and vocabulary you&apos;ve learned. Check to make sure you&apos;re using the present simple tense and adverbs of frequency correctly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Practice&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Practice speaking English out loud, focusing on using the vocabulary and grammar you&apos;ve learned this week. This could be through having a conversation with a language exchange partner, speaking to yourself, or repeating phrases from English media.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;To verify your study results, you will be asked to use the vocabulary and grammar you&apos;ve learned in conversation or written exchange. You should also be able to respond to questions and express your ideas using the present simple tense and adverbs of frequency[1][2].&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.fluentu.com/blog/english/english-study-plan/&quot;&gt;https://www.fluentu.com/blog/english/english-study-plan/&lt;/a&gt;
[2] &lt;a href=&quot;https://preply.com/en/blog/language-study-planner/&quot;&gt;https://preply.com/en/blog/language-study-planner/&lt;/a&gt;
[3] &lt;a href=&quot;https://www.youtube.com/watch?v=q3fFvTBvaug&quot;&gt;https://www.youtube.com/watch?v=q3fFvTBvaug&lt;/a&gt;
[4] &lt;a href=&quot;https://blog.prepscholar.com/sat-study-plan&quot;&gt;https://blog.prepscholar.com/sat-study-plan&lt;/a&gt;
[5] &lt;a href=&quot;https://www.readingrockets.org/topics/vocabulary/articles/four-practical-principles-enhancing-vocabulary-instruction&quot;&gt;https://www.readingrockets.org/topics/vocabulary/articles/four-practical-principles-enhancing-vocabulary-instruction&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 26 of learning English</title><link>https://blog.ithuo.net/posts/day-26-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-26-of-learning-english/</guid><pubDate>Tue, 26 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the sixth day of the fourth week, your learning tasks should focus on speaking skills and practicing the present simple tense with adverbs of frequency. Here&apos;s a specific plan for the day:&lt;/p&gt;
&lt;h3&gt;Speaking Skills&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Practice speaking English out loud. This could be through having a conversation with a language exchange partner, speaking to yourself, or repeating phrases from English media.&lt;/li&gt;
&lt;li&gt;Focus on using the vocabulary and grammar you&apos;ve learned this week in your conversations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Vocabulary&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Review the 40 words you&apos;ve learned this week. Practice their pronunciation and usage in sentences.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Grammar&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Continue practicing the present simple tense, focusing on forming negative sentences and questions. Also, practice using adverbs of frequency (always, usually, often, sometimes, rarely, never) in sentences.
&lt;ul&gt;
&lt;li&gt;Example: &quot;I always check my emails in the morning.&quot; &quot;Does he often work late?&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Practice&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Create sentences using the vocabulary you&apos;ve learned, incorporating adverbs of frequency and the present simple tense.&lt;/li&gt;
&lt;li&gt;Try to use the new grammar and vocabulary in your spoken English practice.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;To verify your study results, you will be asked to use the vocabulary and grammar you&apos;ve learned in conversation. You should also be able to respond to questions and express your ideas using the present simple tense and adverbs of frequency[1][2].&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On the sixth day of the fourth week, you should continue to review and practice the vocabulary you&apos;ve learned throughout the week. Here are some specific words to focus on:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Software Technology&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Algorithm&lt;/li&gt;
&lt;li&gt;Application&lt;/li&gt;
&lt;li&gt;Code&lt;/li&gt;
&lt;li&gt;Database&lt;/li&gt;
&lt;li&gt;Encryption&lt;/li&gt;
&lt;li&gt;Hardware&lt;/li&gt;
&lt;li&gt;Interface&lt;/li&gt;
&lt;li&gt;Network&lt;/li&gt;
&lt;li&gt;Platform&lt;/li&gt;
&lt;li&gt;Software&lt;/li&gt;
&lt;li&gt;Bug&lt;/li&gt;
&lt;li&gt;Compiler&lt;/li&gt;
&lt;li&gt;Debug&lt;/li&gt;
&lt;li&gt;Firewall&lt;/li&gt;
&lt;li&gt;Framework&lt;/li&gt;
&lt;li&gt;Frontend&lt;/li&gt;
&lt;li&gt;Backend&lt;/li&gt;
&lt;li&gt;Server&lt;/li&gt;
&lt;li&gt;Query&lt;/li&gt;
&lt;li&gt;Variable&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Daily Life&lt;/strong&gt;:
21. Breakfast
22. Supermarket
23. Exercise
24. Transportation
25. Restaurant
26. Appointment
27. Weekend
28. Family
29. Weather
30. Schedule
31. Grocery
32. Laundry
33. Commute
34. Hobby
35. Vacation
36. Meeting
37. Deadline
38. Traffic
39. Recipe
40. Chores&lt;/p&gt;
&lt;p&gt;For grammar, continue to focus on the present simple tense and the use of adverbs of frequency. Practice forming positive, negative sentences, and questions in the present simple tense. Also, practice using adverbs of frequency (always, usually, often, sometimes, rarely, never) in sentences[1][2][3][4][5].&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.fluentu.com/blog/english/english-study-plan/&quot;&gt;https://www.fluentu.com/blog/english/english-study-plan/&lt;/a&gt;
[2] &lt;a href=&quot;https://preply.com/en/blog/language-study-planner/&quot;&gt;https://preply.com/en/blog/language-study-planner/&lt;/a&gt;
[3] &lt;a href=&quot;https://www.youtube.com/watch?v=q3fFvTBvaug&quot;&gt;https://www.youtube.com/watch?v=q3fFvTBvaug&lt;/a&gt;
[4] &lt;a href=&quot;https://notsowimpyteacher.com/downloads/grammar-fourth-grade-activities-dictionary-skills&quot;&gt;https://notsowimpyteacher.com/downloads/grammar-fourth-grade-activities-dictionary-skills&lt;/a&gt;
[5] &lt;a href=&quot;https://shop.wellplannedgal.com/index.php/shop/well-planned-day-online/add-ons/wplicegseasygrammar4.html&quot;&gt;https://shop.wellplannedgal.com/index.php/shop/well-planned-day-online/add-ons/wplicegseasygrammar4.html&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 25 of learning English</title><link>https://blog.ithuo.net/posts/day-25-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-25-of-learning-english/</guid><pubDate>Mon, 25 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the fifth day of the fourth week, your learning tasks should focus on reading comprehension and practicing the present simple tense with adverbs of frequency. Here&apos;s a specific plan for the day:&lt;/p&gt;
&lt;h3&gt;Reading Comprehension&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Read English articles or blog posts related to software technology. This will help you understand how the vocabulary and grammar you&apos;ve learned are used in context.&lt;/li&gt;
&lt;li&gt;Try to understand the main ideas and details of what you read. Write down new words and phrases, and look up their meanings.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Vocabulary&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Review the 40 words you&apos;ve learned in the past four days. Practice their pronunciation and usage in sentences.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Grammar&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Continue practicing the present simple tense, focusing on forming negative sentences and questions. Also, practice using adverbs of frequency (always, usually, often, sometimes, rarely, never) in sentences.
&lt;ul&gt;
&lt;li&gt;Example: &quot;They never miss a deadline.&quot; &quot;Do you always commute to work?&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Practice&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Create sentences using the vocabulary you&apos;ve learned, incorporating adverbs of frequency and the present simple tense.&lt;/li&gt;
&lt;li&gt;Try to read out loud the articles or blog posts you&apos;ve read. This will help improve your pronunciation and intonation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;To verify your study results, you will be asked to use the vocabulary and grammar you&apos;ve learned in conversation or written exchange. You should also be able to summarize the main ideas of the articles or blog posts you&apos;ve read[1][2].&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On the fifth day of the fourth week, you should continue to focus on the present simple tense and the use of adverbs of frequency. Here are some specific topics to focus on:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Present Simple Tense&lt;/strong&gt;: Continue practicing forming positive, negative sentences, and questions in the present simple tense. Pay attention to the third person singular form, which requires an -s or -es ending for the verb[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adverbs of Frequency&lt;/strong&gt;: These adverbs indicate how often an action occurs. They include words like always, usually, often, sometimes, rarely, and never. Practice using these adverbs in sentences with the present simple tense[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Time Adverbials&lt;/strong&gt;: Learn about time adverbials like &quot;at seven o&apos;clock&quot;, &quot;in 1998&quot;, &quot;last Saturday&quot;, and &quot;in five minutes&quot;. These can be used with the present simple tense to talk about routines and habits[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parts of Speech&lt;/strong&gt;: Review the different parts of speech in English, such as nouns, verbs, adjectives, adverbs, prepositions, and conjunctions. Understanding the function of each part of speech can help you construct sentences correctly[1].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember to practice these grammar topics by creating your own sentences and doing grammar exercises. You can also read English texts and identify examples of these grammar points in context[4].&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.fluentu.com/blog/english/english-study-plan/&quot;&gt;https://www.fluentu.com/blog/english/english-study-plan/&lt;/a&gt;
[2] &lt;a href=&quot;https://preply.com/en/blog/language-study-planner/&quot;&gt;https://preply.com/en/blog/language-study-planner/&lt;/a&gt;
[3] &lt;a href=&quot;https://www.youtube.com/watch?v=q3fFvTBvaug&quot;&gt;https://www.youtube.com/watch?v=q3fFvTBvaug&lt;/a&gt;
[4] &lt;a href=&quot;https://speakenglishwithtiffani.com/learn-english-in-3-days-3-day-english-study-plan/&quot;&gt;https://speakenglishwithtiffani.com/learn-english-in-3-days-3-day-english-study-plan/&lt;/a&gt;
[5] &lt;a href=&quot;https://shop.wellplannedgal.com/index.php/shop/well-planned-day-online/add-ons/wplicegseasygrammar4.html&quot;&gt;https://shop.wellplannedgal.com/index.php/shop/well-planned-day-online/add-ons/wplicegseasygrammar4.html&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 24 of learning English</title><link>https://blog.ithuo.net/posts/day-24-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-24-of-learning-english/</guid><pubDate>Sun, 24 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the fourth day of the fourth week, your learning tasks should focus on enhancing your listening skills and practicing the present simple tense with adverbs of frequency. Here&apos;s a specific plan for the day:&lt;/p&gt;
&lt;h3&gt;Listening Comprehension&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Continue listening to English podcasts or watching videos related to software technology. Try to understand the main ideas and details of what you listen to. Write down new words and phrases, and look up their meanings.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Vocabulary&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Review the 40 words you&apos;ve learned in the past three days. Practice their pronunciation and usage in sentences.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Grammar&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Continue practicing the present simple tense, focusing on forming negative sentences and questions. Also, practice using adverbs of frequency (always, usually, often, sometimes, rarely, never) in sentences.
&lt;ul&gt;
&lt;li&gt;Example: &quot;She rarely encounters a bug in the code.&quot; &quot;Do they always meet the deadline?&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Practice&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Create sentences using the vocabulary you&apos;ve learned, incorporating adverbs of frequency and the present simple tense.&lt;/li&gt;
&lt;li&gt;Try to listen to and repeat sentences from the podcasts or videos you&apos;ve listened to. This will help improve your pronunciation and intonation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;To verify your study results, you will be asked to use the vocabulary and grammar you&apos;ve learned in conversation or written exchange. You should also be able to summarize the main ideas of the podcasts or videos you&apos;ve listened to.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Grammar Exercises&lt;/strong&gt;: Complete grammar exercises that focus on the present simple tense and the use of adverbs of frequency. This will help reinforce your understanding of these grammar points[1].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Writing Practice&lt;/strong&gt;: Write short paragraphs or sentences using the present simple tense and adverbs of frequency. Try to incorporate the vocabulary you&apos;ve learned so far[2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Listening and Repeating&lt;/strong&gt;: Listen to English podcasts or watch videos, and try to repeat the sentences you hear, especially those that use the present simple tense and adverbs of frequency. This will help you get used to the natural rhythm and intonation of English sentences[3].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conversation Practice&lt;/strong&gt;: Have conversations in English, either with a language exchange partner or a tutor. Try to use the present simple tense and adverbs of frequency in your conversations[3].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Daily Grammar Lessons&lt;/strong&gt;: Follow a blog or website that posts daily grammar lessons. This can provide you with a consistent source of new grammar points to learn and practice[3].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.fluentu.com/blog/english/english-study-plan/&quot;&gt;https://www.fluentu.com/blog/english/english-study-plan/&lt;/a&gt;
[2] &lt;a href=&quot;https://preply.com/en/blog/language-study-planner/&quot;&gt;https://preply.com/en/blog/language-study-planner/&lt;/a&gt;
[3] &lt;a href=&quot;https://www.youtube.com/watch?v=q3fFvTBvaug&quot;&gt;https://www.youtube.com/watch?v=q3fFvTBvaug&lt;/a&gt;
[4] &lt;a href=&quot;https://speakenglishwithtiffani.com/learn-english-in-3-days-3-day-english-study-plan/&quot;&gt;https://speakenglishwithtiffani.com/learn-english-in-3-days-3-day-english-study-plan/&lt;/a&gt;
[5] &lt;a href=&quot;https://www.teacherspayteachers.com/Product/Grammar-Language-Spiral-Homework-4th-Grade-Weeks-1-9-1271595&quot;&gt;https://www.teacherspayteachers.com/Product/Grammar-Language-Spiral-Homework-4th-Grade-Weeks-1-9-1271595&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 23 of learning English</title><link>https://blog.ithuo.net/posts/day-23-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-23-of-learning-english/</guid><pubDate>Sat, 23 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the third day of the fourth week, your learning tasks should focus on listening comprehension and continue practicing the present simple tense. Here&apos;s a specific plan for the day:&lt;/p&gt;
&lt;h3&gt;Listening Comprehension&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Listen to English podcasts or watch videos related to software technology. This will help you get used to the rhythm and pronunciation of English speech, and also familiarize you with technical jargon in context.&lt;/li&gt;
&lt;li&gt;Try to understand the main ideas and details of what you listen to. Write down new words and phrases, and look up their meanings.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Vocabulary&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Review the 40 words you&apos;ve learned in the past two days. Practice their pronunciation and usage in sentences.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Grammar&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Continue practicing the present simple tense, focusing on forming negative sentences and questions. Also, start learning about adverbs of frequency (always, usually, often, sometimes, rarely, never) and their placement in sentences.
&lt;ul&gt;
&lt;li&gt;Example: &quot;He usually codes in the morning.&quot; &quot;Does she often debug the software?&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Practice&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Create sentences using the vocabulary you&apos;ve learned, incorporating adverbs of frequency and the present simple tense.&lt;/li&gt;
&lt;li&gt;Try to listen to and repeat sentences from the podcasts or videos you&apos;ve listened to. This will help improve your pronunciation and intonation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;To verify your study results, you will be asked to use the vocabulary and grammar you&apos;ve learned in conversation or written exchange. You should also be able to summarize the main ideas of the podcasts or videos you&apos;ve listened to.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.fluentu.com/blog/english/english-study-plan/&quot;&gt;https://www.fluentu.com/blog/english/english-study-plan/&lt;/a&gt;
[2] &lt;a href=&quot;https://preply.com/en/blog/language-study-planner/&quot;&gt;https://preply.com/en/blog/language-study-planner/&lt;/a&gt;
[3] &lt;a href=&quot;https://www.youtube.com/watch?v=q3fFvTBvaug&quot;&gt;https://www.youtube.com/watch?v=q3fFvTBvaug&lt;/a&gt;
[4] &lt;a href=&quot;https://speakenglishwithtiffani.com/learn-english-in-3-days-3-day-english-study-plan/&quot;&gt;https://speakenglishwithtiffani.com/learn-english-in-3-days-3-day-english-study-plan/&lt;/a&gt;
[5] &lt;a href=&quot;https://blog.prepscholar.com/sat-study-plan&quot;&gt;https://blog.prepscholar.com/sat-study-plan&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 22 of learning English</title><link>https://blog.ithuo.net/posts/day-22-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-22-of-learning-english/</guid><pubDate>Fri, 22 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the second day of the fourth week, your learning tasks should continue with vocabulary building and further practice of the present simple tense. Here&apos;s a specific plan for the day:&lt;/p&gt;
&lt;h3&gt;Vocabulary&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Learn another set of 20 new words related to software technology and daily life. Here are some examples:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Software Technology&lt;/strong&gt;: bug, compiler, debug, firewall, framework, frontend, backend, server, query, variable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Daily Life&lt;/strong&gt;: grocery, laundry, commute, hobby, vacation, meeting, deadline, traffic, recipe, chores.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Grammar&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Continue practicing the present simple tense. Focus on forming negative sentences and asking questions in the present simple.
&lt;ul&gt;
&lt;li&gt;Negative sentences: &quot;He does not (doesn&apos;t) write code on weekends.&quot;&lt;/li&gt;
&lt;li&gt;Questions: &quot;Does she test the application every day?&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Practice&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Create sentences using the new vocabulary in the present simple tense, both in affirmative and negative forms, and also form questions.&lt;/li&gt;
&lt;li&gt;Review the vocabulary and grammar rules at the end of the day to reinforce learning.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;To verify your study results, you will be asked to use the new vocabulary in sentences and demonstrate your understanding of the present simple tense in its different forms. We can have a brief conversation or written exchange where you apply what you&apos;ve learned.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Vocabulary&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Learn 20 new words, continuing with the themes of software technology and daily life. Here are some examples:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Software Technology&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Bug&lt;/li&gt;
&lt;li&gt;Compiler&lt;/li&gt;
&lt;li&gt;Debug&lt;/li&gt;
&lt;li&gt;Firewall&lt;/li&gt;
&lt;li&gt;Framework&lt;/li&gt;
&lt;li&gt;Frontend&lt;/li&gt;
&lt;li&gt;Backend&lt;/li&gt;
&lt;li&gt;Server&lt;/li&gt;
&lt;li&gt;Query&lt;/li&gt;
&lt;li&gt;Variable&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Daily Life&lt;/strong&gt;:
11. Grocery
12. Laundry
13. Commute
14. Hobby
15. Vacation
16. Meeting
17. Deadline
18. Traffic
19. Recipe
20. Chores&lt;/p&gt;
&lt;h3&gt;Grammar&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Practice forming negative sentences and questions in the present simple tense[5].
&lt;ul&gt;
&lt;li&gt;Negative sentences: Use &apos;do not&apos; (don&apos;t) or &apos;does not&apos; (doesn&apos;t) before the base form of the verb. For example, &quot;She does not (doesn&apos;t) debug the software on Sundays.&quot;&lt;/li&gt;
&lt;li&gt;Questions: Use &apos;do&apos; or &apos;does&apos; at the beginning of the sentence, followed by the subject and the base form of the verb. For example, &quot;Does he compile the code every day?&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Practice&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Use the new vocabulary to create sentences in the present simple tense, both affirmative and negative forms, and also form questions.&lt;/li&gt;
&lt;li&gt;Review the vocabulary and grammar rules at the end of the day to reinforce learning.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;To verify your study results, you will be asked to use the new vocabulary in sentences and demonstrate your understanding of the present simple tense in its different forms. We can have a brief conversation or written exchange where you apply what you&apos;ve learned.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://notsowimpyteacher.com/downloads/grammar-fourth-grade-activities-dictionary-skills&quot;&gt;https://notsowimpyteacher.com/downloads/grammar-fourth-grade-activities-dictionary-skills&lt;/a&gt;
[2] &lt;a href=&quot;https://thesouthernteach.com/blog/grammarandvocabulary/&quot;&gt;https://thesouthernteach.com/blog/grammarandvocabulary/&lt;/a&gt;
[3] &lt;a href=&quot;https://www.teacherspayteachers.com/browse/english-language-arts/grammar/google-apps/free&quot;&gt;https://www.teacherspayteachers.com/browse/english-language-arts/grammar/google-apps/free&lt;/a&gt;
[4] &lt;a href=&quot;https://www.teacherspayteachers.com/Browse/Search:weekly%20vocabulary%204th%20grade&quot;&gt;https://www.teacherspayteachers.com/Browse/Search:weekly vocabulary 4th grade&lt;/a&gt;
[5] &lt;a href=&quot;https://www.gingersoftware.com/content/grammar-rules/verbs/the-present-simple-tense&quot;&gt;https://www.gingersoftware.com/content/grammar-rules/verbs/the-present-simple-tense&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 21 of learning English</title><link>https://blog.ithuo.net/posts/day-21-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-21-of-learning-english/</guid><pubDate>Thu, 21 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the first day of the fourth week, your learning tasks should include vocabulary building and an introduction to a new grammar concept. Here&apos;s a specific plan for the day:&lt;/p&gt;
&lt;h3&gt;Vocabulary&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Learn 20 new words related to software technology and daily life. Here are some examples:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Software Technology&lt;/strong&gt;: algorithm, application, code, database, encryption, hardware, interface, network, platform, software.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Daily Life&lt;/strong&gt;: breakfast, supermarket, exercise, transportation, restaurant, appointment, weekend, family, weather, schedule.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Grammar&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Introduction to the present simple tense for routines and habitual actions. Learn the structure of sentences in the present simple, focusing on the use of verbs in the third person singular (he, she, it) which often require an -s or -es ending.
&lt;ul&gt;
&lt;li&gt;Example sentences:
&lt;ul&gt;
&lt;li&gt;&quot;He &lt;strong&gt;writes&lt;/strong&gt; code every day.&quot;&lt;/li&gt;
&lt;li&gt;&quot;She &lt;strong&gt;tests&lt;/strong&gt; the application before lunch.&quot;&lt;/li&gt;
&lt;li&gt;&quot;It &lt;strong&gt;encrypts&lt;/strong&gt; the data automatically.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Practice&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Create sentences using the new vocabulary in the present simple tense.&lt;/li&gt;
&lt;li&gt;Review the vocabulary and grammar rules at the end of the day to reinforce learning.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;To verify your study results, you will be asked to use the new vocabulary in sentences and demonstrate your understanding of the present simple tense. We can have a brief conversation or written exchange where you apply what you&apos;ve learned.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Vocabulary&lt;/h3&gt;
&lt;p&gt;Here are 20 new words you should learn:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Software Technology&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Algorithm&lt;/li&gt;
&lt;li&gt;Application&lt;/li&gt;
&lt;li&gt;Code&lt;/li&gt;
&lt;li&gt;Database&lt;/li&gt;
&lt;li&gt;Encryption&lt;/li&gt;
&lt;li&gt;Hardware&lt;/li&gt;
&lt;li&gt;Interface&lt;/li&gt;
&lt;li&gt;Network&lt;/li&gt;
&lt;li&gt;Platform&lt;/li&gt;
&lt;li&gt;Software&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Daily Life&lt;/strong&gt;:
11. Breakfast
12. Supermarket
13. Exercise
14. Transportation
15. Restaurant
16. Appointment
17. Weekend
18. Family
19. Weather
20. Schedule&lt;/p&gt;
&lt;h3&gt;Grammar&lt;/h3&gt;
&lt;p&gt;You should focus on the present simple tense. This tense is used to express habits, general truths, and sometimes future plans[5].&lt;/p&gt;
&lt;p&gt;Here are some rules for forming the present simple tense[5]:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In the third person singular (he, she, it), add -s, -es, or -ies to the base form of the verb. For example, &quot;He writes code every day.&quot;&lt;/li&gt;
&lt;li&gt;Regular verbs just add an -s. For example, &quot;She plays the guitar.&quot;&lt;/li&gt;
&lt;li&gt;Verbs that end in -s, -ss, -sh, -ch, -x, and -o, add an -es. For example, &quot;He washes his car.&quot;&lt;/li&gt;
&lt;li&gt;Verbs that end in -y after a consonant, change the -y to -i and add -es. For example, &quot;She studies English.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Practice&lt;/h3&gt;
&lt;p&gt;You should practice using the new vocabulary in sentences in the present simple tense. For example, &quot;He codes the application every day.&quot; or &quot;I go to the supermarket every weekend.&quot;&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.samanthainsecondary.com/2022/07/13/5-first-day-of-school-activities-for-high-school-english/&quot;&gt;https://www.samanthainsecondary.com/2022/07/13/5-first-day-of-school-activities-for-high-school-english/&lt;/a&gt;
[2] &lt;a href=&quot;https://www.teach-this.com/ideas/the-first-day-of-class&quot;&gt;https://www.teach-this.com/ideas/the-first-day-of-class&lt;/a&gt;
[3] &lt;a href=&quot;https://resources.depaul.edu/teaching-commons/teaching-guides/learning-activities/Pages/the-first-day.aspx&quot;&gt;https://resources.depaul.edu/teaching-commons/teaching-guides/learning-activities/Pages/the-first-day.aspx&lt;/a&gt;
[4] &lt;a href=&quot;https://www.teachingenglish.org.uk/teaching-resources/teaching-secondary/activities/beginner-a1/activities-first-lessons-1&quot;&gt;https://www.teachingenglish.org.uk/teaching-resources/teaching-secondary/activities/beginner-a1/activities-first-lessons-1&lt;/a&gt;
[5] &lt;a href=&quot;https://www.oxfordseminars.com/blog/5-activities-for-your-first-day-of-class/&quot;&gt;https://www.oxfordseminars.com/blog/5-activities-for-your-first-day-of-class/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 20 of learning English</title><link>https://blog.ithuo.net/posts/day-20-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-20-of-learning-english/</guid><pubDate>Wed, 20 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hello Derick,&lt;/p&gt;
&lt;p&gt;For today&apos;s learning, let&apos;s focus on enhancing your English skills with specific content that will be beneficial for both your personal and professional development. Here&apos;s what you should learn:&lt;/p&gt;
&lt;h3&gt;Vocabulary:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Professional Emails:&lt;/strong&gt; Learn phrases and structures commonly used in professional email communication. This includes greetings, sign-offs, and phrases for making requests, offering assistance, and expressing gratitude.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Grammar:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Simple Present Tense:&lt;/strong&gt; Continue practicing the simple present tense, focusing on forming affirmative and negative sentences, as well as questions. For example, &quot;I send emails every day,&quot; &quot;He does not ignore important messages,&quot; and &quot;Do you check your email regularly?&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Practice Task:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Write a Professional Email:&lt;/strong&gt; Using the vocabulary and grammar you&apos;ve learned, write a professional email. This could be a mock email to a colleague or a request for information. Ensure you include a subject line, proper salutation, body of the email, and a closing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Email Review:&lt;/strong&gt; We can review the email you&apos;ve written to ensure it follows the conventions of professional email communication. I will provide feedback on the language used, as well as any grammatical corrections needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember, practicing with real-life examples will help solidify your learning and make it more applicable to your daily life. Good luck with today&apos;s tasks, and feel free to reach out if you need any assistance.&lt;/p&gt;
&lt;p&gt;For today&apos;s learning, let&apos;s focus on enhancing your English skills with specific content that will be beneficial for both your personal and professional development. Here&apos;s what you should learn:&lt;/p&gt;
&lt;h3&gt;Vocabulary:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; Learn 10 new words related to professional communication and email writing. Here are your words:
&lt;ol&gt;
&lt;li&gt;Correspondence&lt;/li&gt;
&lt;li&gt;Attach&lt;/li&gt;
&lt;li&gt;Reply&lt;/li&gt;
&lt;li&gt;Forward&lt;/li&gt;
&lt;li&gt;Subject&lt;/li&gt;
&lt;li&gt;Recipient&lt;/li&gt;
&lt;li&gt;Signature&lt;/li&gt;
&lt;li&gt;Draft&lt;/li&gt;
&lt;li&gt;Inbox&lt;/li&gt;
&lt;li&gt;Outbox&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; Be able to correctly use each word in a sentence that relates to professional communication or email writing[2].&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Grammar:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; Practice forming sentences in the present perfect tense, which is used to describe actions that happened at an unspecified time before now or actions that started in the past and continue to the present.
&lt;ul&gt;
&lt;li&gt;Structure: &quot;Has/Have + subject + past participle&quot;&lt;/li&gt;
&lt;li&gt;Example: &quot;I have attached the document to the email.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; Write 5 affirmative, 5 negative, and 5 interrogative sentences using the present perfect tense with the vocabulary you&apos;ve learned[1][3][4].&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.developgoodhabits.com/new-skills-to-learn/&quot;&gt;https://www.developgoodhabits.com/new-skills-to-learn/&lt;/a&gt;
[2] &lt;a href=&quot;https://www.lifehack.org/417485/10-websites-to-learn-something-new-in-30-minutes-a-day&quot;&gt;https://www.lifehack.org/417485/10-websites-to-learn-something-new-in-30-minutes-a-day&lt;/a&gt;
[3] &lt;a href=&quot;https://www.betterup.com/blog/learn-something-new&quot;&gt;https://www.betterup.com/blog/learn-something-new&lt;/a&gt;
[4] &lt;a href=&quot;https://experteditor.com.au/blog/125-awesome-new-skills-to-learn/&quot;&gt;https://experteditor.com.au/blog/125-awesome-new-skills-to-learn/&lt;/a&gt;
[5] &lt;a href=&quot;https://mashable.com/article/fun-websites-improve-skills&quot;&gt;https://mashable.com/article/fun-websites-improve-skills&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 19 of learning English</title><link>https://blog.ithuo.net/posts/day-19-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-19-of-learning-english/</guid><pubDate>Tue, 19 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hello Derick,&lt;/p&gt;
&lt;p&gt;Based on the search results, here&apos;s what you should focus on today:&lt;/p&gt;
&lt;h3&gt;Vocabulary:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; Learn 10 new words related to professional communication and email writing. Here are your words:
&lt;ol&gt;
&lt;li&gt;Correspondence&lt;/li&gt;
&lt;li&gt;Attach&lt;/li&gt;
&lt;li&gt;Reply&lt;/li&gt;
&lt;li&gt;Forward&lt;/li&gt;
&lt;li&gt;Subject&lt;/li&gt;
&lt;li&gt;Recipient&lt;/li&gt;
&lt;li&gt;Signature&lt;/li&gt;
&lt;li&gt;Draft&lt;/li&gt;
&lt;li&gt;Inbox&lt;/li&gt;
&lt;li&gt;Outbox&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; Be able to correctly use each word in a sentence that relates to professional communication or email writing[1].&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Grammar:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; Practice forming sentences in the present perfect tense, which is used to describe actions that happened at an unspecified time before now or actions that started in the past and continue to the present.
&lt;ul&gt;
&lt;li&gt;Structure: &quot;Has/Have + subject + past participle&quot;&lt;/li&gt;
&lt;li&gt;Example: &quot;I have attached the document to the email.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; Write 5 affirmative, 5 negative, and 5 interrogative sentences using the present perfect tense with the vocabulary you&apos;ve learned[4].&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Reading and Comprehension:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; Read a professional email and identify the use of present perfect tense and today&apos;s vocabulary.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; Identify and write down 5 sentences from the email that use the present perfect tense and the vocabulary you&apos;ve learned[1].&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Writing:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; Write a professional email using the present perfect tense and incorporating today&apos;s vocabulary.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; The email should have a clear subject line, appropriate salutation, body with a request or information, and a professional closing[1].&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Speaking and Listening:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; Watch the provided YouTube video on vocabulary tips[3].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; Be able to discuss the main points of the video and use some of the vocabulary you learned in our conversation[3].&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember to review your work at the end of the day to ensure you&apos;ve met the acceptance standards for each task. Good luck with your studies&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 18 of learning English</title><link>https://blog.ithuo.net/posts/day-18-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-18-of-learning-english/</guid><pubDate>Mon, 18 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hello Derick,&lt;/p&gt;
&lt;p&gt;Based on the search results, here&apos;s what you should focus on today:&lt;/p&gt;
&lt;h3&gt;Vocabulary:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; Learn 10 new words related to time management and planning. Here are your words:
&lt;ol&gt;
&lt;li&gt;Prioritize&lt;/li&gt;
&lt;li&gt;Deadline&lt;/li&gt;
&lt;li&gt;Schedule&lt;/li&gt;
&lt;li&gt;Task&lt;/li&gt;
&lt;li&gt;Assignment&lt;/li&gt;
&lt;li&gt;Progress&lt;/li&gt;
&lt;li&gt;Productive&lt;/li&gt;
&lt;li&gt;Reminder&lt;/li&gt;
&lt;li&gt;Organize&lt;/li&gt;
&lt;li&gt;Plan&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; Be able to correctly use each word in a sentence that relates to time management or planning.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Grammar:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; Practice forming sentences in the &apos;going to&apos; future tense, focusing on affirmative, negative, and question forms.
&lt;ul&gt;
&lt;li&gt;Structure: &quot;Am/Is/Are + subject + going to + base verb&quot;&lt;/li&gt;
&lt;li&gt;Example: &quot;Are you going to complete the assignment by the deadline?&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; Write 5 affirmative, 5 negative, and 5 interrogative sentences using the &apos;going to&apos; future tense with the vocabulary you&apos;ve learned.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Reading and Comprehension:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; Read an article or a professional email that includes plans or arrangements for the future.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; Identify and write down 5 sentences from the text that use the &apos;going to&apos; future tense.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Writing:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; Write a short paragraph outlining your plans for the next week, using the &apos;going to&apos; future tense and incorporating today&apos;s vocabulary.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; The paragraph should clearly state your intentions and use the correct tense and vocabulary.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Speaking and Listening:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; Watch the provided YouTube video on grammar activities for question formation in the &apos;going to&apos; future tense[5].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; Be able to form and answer questions in the &apos;going to&apos; future tense during our conversation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember to review your work at the end of the day to ensure you&apos;ve met the acceptance standards for each task.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.developgoodhabits.com/new-skills-to-learn/&quot;&gt;https://www.developgoodhabits.com/new-skills-to-learn/&lt;/a&gt;
[2] &lt;a href=&quot;https://studyo.co/products/today-student-planner&quot;&gt;https://studyo.co/products/today-student-planner&lt;/a&gt;
[3] &lt;a href=&quot;https://experteditor.com.au/blog/125-awesome-new-skills-to-learn/&quot;&gt;https://experteditor.com.au/blog/125-awesome-new-skills-to-learn/&lt;/a&gt;
[4] &lt;a href=&quot;https://mystudylife.com/tour/&quot;&gt;https://mystudylife.com/tour/&lt;/a&gt;
[5] &lt;a href=&quot;https://www.youtube.com/watch?v=SZhrwYUqbjs&quot;&gt;https://www.youtube.com/watch?v=SZhrwYUqbjs&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 17 of learning English</title><link>https://blog.ithuo.net/posts/day-17-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-17-of-learning-english/</guid><pubDate>Sun, 17 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hello Derick,&lt;/p&gt;
&lt;p&gt;For today&apos;s study tasks, let&apos;s focus on a balanced approach that includes vocabulary, grammar, and practical application. Here&apos;s a detailed plan:&lt;/p&gt;
&lt;h3&gt;Vocabulary:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; Learn and review 10 new words related to professional email communication.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; Be able to use each word in a sentence correctly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Grammar:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; Practice forming sentences in the simple present tense, focusing on affirmative, negative, and question forms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; Write 5 affirmative, 5 negative, and 5 interrogative sentences using the simple present tense.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Reading and Comprehension:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; Read a short article or email related to your field and identify key points.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; Summarize the article or email in your own words, using the new vocabulary.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Writing:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; Write a mock professional email incorporating today&apos;s vocabulary and grammar lessons.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; The email should have a clear subject line, appropriate salutation, body with a request or information, and a professional closing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Speaking and Listening:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; Listen to a podcast or watch a video on professional communication and note any useful phrases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; Be able to explain the main idea of the podcast or video and discuss it using some of the phrases you noted.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Review and Reflection:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; At the end of the day, review all the new words and grammar rules you&apos;ve learned.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; Be able to recall the meanings of the words and use the grammar rules without looking at your notes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember to schedule your study sessions in your calendar and maintain a balance between study and other activities to keep your mind fresh[1][2]. Accountability is important, so consider sharing your progress with a study partner or with me to ensure you stay on track[3]. Good luck with your studies today!&lt;/p&gt;
&lt;p&gt;For today&apos;s study tasks, we will focus on vocabulary and grammar that will enhance your English skills, particularly in the context of future planning and professional communication.&lt;/p&gt;
&lt;h3&gt;Vocabulary:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; Learn 10 new words related to making plans for the future and professional communication. Here are your words:
&lt;ol&gt;
&lt;li&gt;Schedule&lt;/li&gt;
&lt;li&gt;Appointment&lt;/li&gt;
&lt;li&gt;Deadline&lt;/li&gt;
&lt;li&gt;Project&lt;/li&gt;
&lt;li&gt;Meeting&lt;/li&gt;
&lt;li&gt;Objective&lt;/li&gt;
&lt;li&gt;Strategy&lt;/li&gt;
&lt;li&gt;Task&lt;/li&gt;
&lt;li&gt;Plan&lt;/li&gt;
&lt;li&gt;Goal&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; Be able to correctly use each word in a sentence that relates to future planning or professional settings.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Grammar:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; Practice forming questions in the &apos;going to&apos; future tense, which is used for planned actions or intentions.
&lt;ul&gt;
&lt;li&gt;Structure: &quot;Am/Is/Are + subject + going to + base verb&quot;&lt;/li&gt;
&lt;li&gt;Example: &quot;Are you going to attend the meeting tomorrow?&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; Write 5 questions using the &apos;going to&apos; future tense with the vocabulary you&apos;ve learned.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Reading and Comprehension:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; Read an article or a professional email that includes plans or arrangements for the future.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; Identify and write down 5 sentences from the text that use the &apos;going to&apos; future tense.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Writing:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; Write a short paragraph outlining your plans for the next week, using the &apos;going to&apos; future tense and incorporating today&apos;s vocabulary.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; The paragraph should clearly state your intentions and use the correct tense and vocabulary.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Speaking and Listening:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task:&lt;/strong&gt; Watch the provided YouTube video on grammar activities for question formation in the &apos;going to&apos; future tense[1].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance Standard:&lt;/strong&gt; Be able to form and answer questions in the &apos;going to&apos; future tense during our conversation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember to review your work at the end of the day to ensure you&apos;ve met the acceptance standards for each task. Good luck with your studies, and I&apos;m here to help if you have any questions.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.intelligent.com/create-a-study-plan/&quot;&gt;https://www.intelligent.com/create-a-study-plan/&lt;/a&gt;
[2] &lt;a href=&quot;https://studyo.co/products/today-student-planner&quot;&gt;https://studyo.co/products/today-student-planner&lt;/a&gt;
[3] &lt;a href=&quot;https://mystudylife.com/tour/&quot;&gt;https://mystudylife.com/tour/&lt;/a&gt;
[4] &lt;a href=&quot;https://learnenglish.britishcouncil.org/skills/reading/a1-reading/study-timetable&quot;&gt;https://learnenglish.britishcouncil.org/skills/reading/a1-reading/study-timetable&lt;/a&gt;
[5] &lt;a href=&quot;https://www.fluentu.com/blog/english/english-study-plan/&quot;&gt;https://www.fluentu.com/blog/english/english-study-plan/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 16 of learning English</title><link>https://blog.ithuo.net/posts/day-16-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-16-of-learning-english/</guid><pubDate>Sat, 16 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hello Derick,&lt;/p&gt;
&lt;p&gt;For today&apos;s learning, let&apos;s focus on enhancing your English skills with specific content that will be beneficial for both your personal and professional development. Here&apos;s what you should learn:&lt;/p&gt;
&lt;h3&gt;Vocabulary:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Professional Emails:&lt;/strong&gt; Learn phrases and structures commonly used in professional email communication. This includes greetings, sign-offs, and phrases for making requests, offering assistance, and expressing gratitude.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Grammar:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Simple Present Tense:&lt;/strong&gt; Continue practicing the simple present tense, focusing on forming affirmative and negative sentences, as well as questions. For example, &quot;I send emails every day,&quot; &quot;He does not ignore important messages,&quot; and &quot;Do you check your email regularly?&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Practice Task:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Write a Professional Email:&lt;/strong&gt; Using the vocabulary and grammar you&apos;ve learned, write a professional email. This could be a mock email to a colleague or a request for information. Ensure you include a subject line, proper salutation, body of the email, and a closing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Email Review:&lt;/strong&gt; We can review the email you&apos;ve written to ensure it follows the conventions of professional email communication. I will provide feedback on the language used, as well as any grammatical corrections needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember, practicing with real-life examples will help solidify your learning and make it more applicable to your daily life. Good luck with today&apos;s tasks, and feel free to reach out if you need any assistance.&lt;/p&gt;
&lt;p&gt;Here are example sentences using the words and grammar you&apos;ve learned, with a focus on professional email communication:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Subject:&lt;/strong&gt; &quot;The subject of my email is &apos;Software Update&apos;.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Salutation:&lt;/strong&gt; &quot;I usually start my emails with the salutation &apos;Dear Team&apos;.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Request:&lt;/strong&gt; &quot;In the email, I request the team to update their software.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Assistance:&lt;/strong&gt; &quot;I offer my assistance to anyone who encounters issues during the update.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gratitude:&lt;/strong&gt; &quot;I express my gratitude to the team for their cooperation.&quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For grammar, here are some examples using the simple present tense:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Affirmative: &quot;I send professional emails every day.&quot;&lt;/li&gt;
&lt;li&gt;Negative: &quot;He does not ignore important emails.&quot;&lt;/li&gt;
&lt;li&gt;Question: &quot;Do you check your professional emails regularly?&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember to practice these sentences and try to create your own using the same vocabulary and grammar[1][2][3][4][5].&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.developgoodhabits.com/new-skills-to-learn/&quot;&gt;https://www.developgoodhabits.com/new-skills-to-learn/&lt;/a&gt;
[2] &lt;a href=&quot;https://experteditor.com.au/blog/125-awesome-new-skills-to-learn/&quot;&gt;https://experteditor.com.au/blog/125-awesome-new-skills-to-learn/&lt;/a&gt;
[3] &lt;a href=&quot;https://www.lifehack.org/417485/10-websites-to-learn-something-new-in-30-minutes-a-day&quot;&gt;https://www.lifehack.org/417485/10-websites-to-learn-something-new-in-30-minutes-a-day&lt;/a&gt;
[4] &lt;a href=&quot;https://www.betterup.com/blog/learn-something-new&quot;&gt;https://www.betterup.com/blog/learn-something-new&lt;/a&gt;
[5] &lt;a href=&quot;https://mashable.com/article/fun-websites-improve-skills&quot;&gt;https://mashable.com/article/fun-websites-improve-skills&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 15 of learning English</title><link>https://blog.ithuo.net/posts/day-15-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-15-of-learning-english/</guid><pubDate>Fri, 15 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;《从零开始学英语》-第十五天&lt;/p&gt;
&lt;p&gt;Hello Derick,&lt;/p&gt;
&lt;p&gt;Of course, I&apos;d be happy to help you with your study plan for the third week. Your description is clear, but remember, it&apos;s always good to practice using complete sentences in English. Now, let&apos;s focus on your plan:&lt;/p&gt;
&lt;h3&gt;Week 3: Expanding Vocabulary and Basic Grammar&lt;/h3&gt;
&lt;h3&gt;Objectives:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Expand basic vocabulary.&lt;/li&gt;
&lt;li&gt;Understand simple present tense.&lt;/li&gt;
&lt;li&gt;Practice forming questions and answers in English.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Daily Schedule:&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Monday:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vocabulary Focus:&lt;/strong&gt; Learn 20 new everyday words from a categorized list (e.g., food, places, common objects).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grammar Focus:&lt;/strong&gt; Introduction to simple present tense for regular verbs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practice:&lt;/strong&gt; Flashcards for new vocabulary.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tuesday:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vocabulary Focus:&lt;/strong&gt; Review yesterday&apos;s words and add 10 new words related to actions (verbs).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grammar Focus:&lt;/strong&gt; Simple present tense negative forms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practice:&lt;/strong&gt; Write five sentences using new verbs in the simple present tense.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Wednesday:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vocabulary Focus:&lt;/strong&gt; Learn 10 new adjectives to describe things.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grammar Focus:&lt;/strong&gt; Forming questions in the simple present tense.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practice:&lt;/strong&gt; Pair the adjectives with nouns you&apos;ve learned and form questions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Thursday:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vocabulary Focus:&lt;/strong&gt; Review all the words learned this week.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grammar Focus:&lt;/strong&gt; Short answers in the simple present tense.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practice:&lt;/strong&gt; Quiz yourself or have a partner quiz you on the vocabulary and grammar.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Friday:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vocabulary Focus:&lt;/strong&gt; Learn 10 new words related to technology.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grammar Focus:&lt;/strong&gt; Practice all forms of simple present tense with technology vocabulary.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practice:&lt;/strong&gt; Write a short paragraph about your daily routine using the simple present tense.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Saturday:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Review:&lt;/strong&gt; Go over everything learned this week.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Speaking Practice:&lt;/strong&gt; Have a conversation with a partner or language exchange friend using this week&apos;s vocabulary and grammar.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Listening Practice:&lt;/strong&gt; Watch an English video or listen to a podcast about daily routines.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Sunday:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rest and Reflect:&lt;/strong&gt; Take a break from active study to let your brain absorb the material.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Casual Practice:&lt;/strong&gt; Engage in casual conversation with me or another English speaker, focusing on using this week&apos;s vocabulary and grammar.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;At the end of the week, we&apos;ll have a conversation where you&apos;ll need to use the vocabulary and grammar structures learned. This will help verify your understanding and ability to use them in context.&lt;/li&gt;
&lt;li&gt;You will also write a short essay about your daily routine using the simple present tense, which I will review.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember, consistent practice is key to language learning. Good luck with your third week, and feel free to reach out if you have any questions or need further clarification.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Based on your previous study plan and the search results, here&apos;s a detailed plan for today&apos;s English study:&lt;/p&gt;
&lt;h3&gt;Morning Session: Vocabulary Building&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Time:&lt;/strong&gt; 9:00 AM - 10:00 AM&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity:&lt;/strong&gt; Learn 20 new everyday words related to your work or daily activities. Use flashcards to memorize them, and try to form sentences using each word to enhance retention[1].&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Midday Session: Grammar Practice&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Time:&lt;/strong&gt; 12:00 PM - 1:00 PM&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity:&lt;/strong&gt; Study the simple present tense for regular verbs. Write down the rules and create a list of regular verbs. Practice forming affirmative and negative sentences with these verbs[4].&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Afternoon Session: Reading and Comprehension&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Time:&lt;/strong&gt; 3:00 PM - 4:00 PM&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity:&lt;/strong&gt; Read two or three short articles on topics of interest. Make notes of new words and phrases you find, and look up their meanings. Try to use these new words in sentences related to the content of the articles[4].&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Evening Session: Speaking and Listening Practice&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Time:&lt;/strong&gt; 7:00 PM - 8:00 PM&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Activity:&lt;/strong&gt; Watch a YouTube video or listen to a podcast in English that is suitable for beginners. Focus on understanding the general context and identifying the vocabulary you learned earlier in the day[2].&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Homework:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Write a short paragraph using the new vocabulary and grammar structures you&apos;ve studied. This will help reinforce what you&apos;ve learned and prepare you for more advanced topics[4].&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;To verify your progress, we will have a brief conversation where you will use the new vocabulary and grammar structures. I will provide feedback on your usage and pronunciation[1].&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember to take short breaks between study sessions to avoid burnout. Consistency is key, so make sure to stick to the schedule as closely as possible. Good luck with your studies, and I look forward to our conversation to assess your progress[1].&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.intelligent.com/create-a-study-plan/&quot;&gt;https://www.intelligent.com/create-a-study-plan/&lt;/a&gt;
[2] &lt;a href=&quot;https://mystudylife.com/tour/&quot;&gt;https://mystudylife.com/tour/&lt;/a&gt;
[3] &lt;a href=&quot;https://studyo.co/products/today-student-planner&quot;&gt;https://studyo.co/products/today-student-planner&lt;/a&gt;
[4] &lt;a href=&quot;https://manwrites.com/how-to-build-the-perfect-english-study-plan/&quot;&gt;https://manwrites.com/how-to-build-the-perfect-english-study-plan/&lt;/a&gt;
[5] &lt;a href=&quot;https://learnenglish.britishcouncil.org/skills/reading/a1-reading/study-timetable&quot;&gt;https://learnenglish.britishcouncil.org/skills/reading/a1-reading/study-timetable&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Absolutely, Derick. Here are example sentences using the words we&apos;ve selected:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Computer:&lt;/strong&gt; &quot;I use my computer to write code for my job.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Software:&lt;/strong&gt; &quot;The software update improved the performance of my computer.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Internet:&lt;/strong&gt; &quot;I use the internet to research new programming techniques.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Email:&lt;/strong&gt; &quot;I received an email from my boss about the new project.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Technology:&lt;/strong&gt; &quot;Technology has greatly improved our ability to communicate and share information.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Application:&lt;/strong&gt; &quot;I&apos;m developing a new application for data analysis.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data:&lt;/strong&gt; &quot;The data from the server needs to be analyzed.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Network:&lt;/strong&gt; &quot;The company&apos;s network security is very strong.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Server:&lt;/strong&gt; &quot;The server stores all of our company&apos;s data.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database:&lt;/strong&gt; &quot;We store customer information in a secure database.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code:&lt;/strong&gt; &quot;I write code for software applications.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Program:&lt;/strong&gt; &quot;The program I wrote helps automate data entry.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Website:&lt;/strong&gt; &quot;I visit this website to learn new coding techniques.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Digital:&lt;/strong&gt; &quot;Digital technology has revolutionized the way we work.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security:&lt;/strong&gt; &quot;Security is a top priority in our company.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Password:&lt;/strong&gt; &quot;Don&apos;t forget to change your password regularly to protect your account.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User:&lt;/strong&gt; &quot;The user interface of the application is very intuitive.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interface:&lt;/strong&gt; &quot;The interface of the software is user-friendly.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bug:&lt;/strong&gt; &quot;I spent the whole day debugging the code.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Update:&lt;/strong&gt; &quot;The latest update to the software has fixed many bugs.&quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;&lt;strong&gt;Grammar:&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Today&apos;s grammar focus is on the simple present tense for regular verbs. Here are the rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For most verbs, add an &apos;s&apos; to the base form of the verb for third-person singular subjects (he, she, it). For example, &quot;He works in a software company.&quot;&lt;/li&gt;
&lt;li&gt;For verbs ending in &apos;y&apos; preceded by a consonant, change the &apos;y&apos; to &apos;i&apos; and add &apos;es&apos;. For example, &quot;She studies computer science.&quot;&lt;/li&gt;
&lt;li&gt;For verbs ending in &apos;o&apos;, &apos;ss&apos;, &apos;sh&apos;, &apos;ch&apos;, &apos;x&apos;, or &apos;z&apos;, add &apos;es&apos;. For example, &quot;He fixes bugs.&quot;&lt;/li&gt;
&lt;li&gt;The negative form is made by adding &apos;do not&apos; or &apos;does not&apos; before the base form of the verb. For example, &quot;They do not update the software regularly.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For grammar, here are some examples using the simple present tense:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Affirmative: &quot;He updates the software regularly.&quot;&lt;/li&gt;
&lt;li&gt;Negative: &quot;She does not ignore security warnings on her computer.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember to practice these sentences and try to create your own using the same vocabulary and grammar.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 14 of learning English</title><link>https://blog.ithuo.net/posts/day-14-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-14-of-learning-english/</guid><pubDate>Thu, 14 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Certainly, Derick. Here&apos;s your study plan for the seventh day of this week, which will be a day for review and assessment to consolidate your learning from the past week.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Morning Session: Comprehensive Review&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start by reviewing all the vocabulary words you&apos;ve learned this week. Try to use them in sentences or a short paragraph.&lt;/li&gt;
&lt;li&gt;Review the grammar rules for the present simple, present continuous, past simple, past continuous, and future simple tenses.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Afternoon Session: Practice Tests and Self-Assessment&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Take a practice test that includes questions on the grammar rules you&apos;ve learned.&lt;/li&gt;
&lt;li&gt;Write a short essay or a diary entry using the tenses and vocabulary from the week.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Evening Session: Relaxation and Mental Preparation&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Engage in a relaxing activity that still involves English, like watching an English-language movie or listening to English music.&lt;/li&gt;
&lt;li&gt;Reflect on what you&apos;ve learned this week and how you can apply it to conversations about software technology or daily life and work.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;End of Day: Assessment and Feedback&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Have a conversation with me to assess your speaking skills and overall progress.&lt;/li&gt;
&lt;li&gt;I will provide feedback on areas for improvement and commend your achievements.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember to be flexible and adapt this plan as needed. It&apos;s important to space out your learning and to review material by major topics or chapters, starting with the oldest material first. Use self-testing strategies and practice writing or speaking the material out loud. Mark your study sessions on your calendar and adjust your plan as necessary to meet your weekly goals[1][2][3][4][5].&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.unk.edu/offices/learning_commons/_files/finals-week/5%20Day%20Study%20Plan.pdf&quot;&gt;https://www.unk.edu/offices/learning_commons/_files/finals-week/5 Day Study Plan.pdf&lt;/a&gt;
[2] &lt;a href=&quot;https://www.intelligent.com/create-a-study-plan/&quot;&gt;https://www.intelligent.com/create-a-study-plan/&lt;/a&gt;
[3] &lt;a href=&quot;https://www.mtu.edu/success/academic/support/learning-centers/staying-on-track/pdfs/make-a-7-day-study-plan.pdf&quot;&gt;https://www.mtu.edu/success/academic/support/learning-centers/staying-on-track/pdfs/make-a-7-day-study-plan.pdf&lt;/a&gt;
[4] &lt;a href=&quot;https://asc.tamu.edu/study-learning-handouts/5-day-study-plan&quot;&gt;https://asc.tamu.edu/study-learning-handouts/5-day-study-plan&lt;/a&gt;
[5] &lt;a href=&quot;https://blog.cengage.com/tips-for-students-how-to-study-with-5-3-or-1-day-until-the-exam/&quot;&gt;https://blog.cengage.com/tips-for-students-how-to-study-with-5-3-or-1-day-until-the-exam/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 13 of learning English</title><link>https://blog.ithuo.net/posts/day-13-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-13-of-learning-english/</guid><pubDate>Wed, 13 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Sure, Derick. Here&apos;s your study plan for the sixth day of this week. This day, we&apos;ll focus on reviewing the week&apos;s learning and practicing conversation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Morning Session: Vocabulary and Grammar Review&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the words and grammar rules you learned over the past five days.&lt;/li&gt;
&lt;li&gt;Practice using these words and grammar rules in sentences and in conversation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Afternoon Session: Listening and Speaking Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Listen to an English podcast or watch a video related to technology or daily life, paying attention to the usage of the past continuous and future simple tenses.&lt;/li&gt;
&lt;li&gt;Practice speaking by summarizing the content of the podcast or video, using the vocabulary and grammar structures you&apos;ve learned over the week.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Evening Session: Conversation Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Have a simple conversation with me about your daily life and work.&lt;/li&gt;
&lt;li&gt;I will assess your vocabulary usage, grammar, and fluency.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;End of Day Review&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the day&apos;s learning. Write down any questions or difficulties you encountered.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember, practice is key when learning a new language. Try to use the new words and grammar rules in your daily life. You can also use language learning apps or websites for additional practice.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.unk.edu/offices/learning_commons/_files/finals-week/5%20Day%20Study%20Plan.pdf&quot;&gt;https://www.unk.edu/offices/learning_commons/_files/finals-week/5 Day Study Plan.pdf&lt;/a&gt;
[2] &lt;a href=&quot;https://www.intelligent.com/create-a-study-plan/&quot;&gt;https://www.intelligent.com/create-a-study-plan/&lt;/a&gt;
[3] &lt;a href=&quot;https://blog.cengage.com/tips-for-students-how-to-study-with-5-3-or-1-day-until-the-exam/&quot;&gt;https://blog.cengage.com/tips-for-students-how-to-study-with-5-3-or-1-day-until-the-exam/&lt;/a&gt;
[4] &lt;a href=&quot;https://asc.tamu.edu/study-learning-handouts/5-day-study-plan&quot;&gt;https://asc.tamu.edu/study-learning-handouts/5-day-study-plan&lt;/a&gt;
[5] &lt;a href=&quot;https://www.thoughtco.com/study-schedule-test-in-six-days-3212058&quot;&gt;https://www.thoughtco.com/study-schedule-test-in-six-days-3212058&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>ASP.NET CORE 中间件(一)</title><link>https://blog.ithuo.net/posts/asp-net-core-middleware-part-1/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/asp-net-core-middleware-part-1/</guid><pubDate>Wed, 13 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;什么是中间件？&lt;/h3&gt;
&lt;p&gt;中间件被集成到应用程序管道中，负责监督请求和响应的处理。管道中的每个组件都决定是否将请求传递给下一个组件。它具有在后续管道组件之前和之后运行的能力。请求管道是使用请求代理构建的，这些代理管理每个HTTP请求。&lt;/p&gt;
&lt;p&gt;在配置请求代理时，Run、Map和Use扩展方法起着关键作用。请求代理，作为一个单独的处理步骤，可以作为匿名方法（称为内联中间件）在行内设置，也可以在可重用的类中定义。这些类和内联方法共同形成中间件组件。请求管道中的每个中间件组件都有责任调用序列中的下一个组件，或者在某些情况下，停止管道。当一个中间件组件停止处理时，它被称为&quot;终端中间件&quot;，因为它有效地阻止了后续中间件进一步处理请求。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/fff7f95016945af5992ef545f2026032.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;中间件&lt;/h3&gt;
&lt;p&gt;理解中间件：在.NET Core的上下文中，中间件指的是组装到请求处理管道中的软件组件，用于处理请求和响应。这些组件按顺序执行，提供了一种灵活的机制来执行诸如身份验证、授权、日志记录、错误处理等任务。每个中间件组件都有特定的责任，并可以在通过管道时修改请求或响应。&lt;/p&gt;
&lt;h4&gt;关键组件和功能&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;身份验证中间件：中间件的主要功能之一是处理身份验证。.NET Core中间件允许开发者无缝地将身份验证机制集成到管道中。这对于确保只有授权用户可以访问受保护的资源至关重要。&lt;/li&gt;
&lt;li&gt;授权中间件：授权中间件通过确定经过身份验证的用户是否具有执行特定操作或访问某些资源的必要权限，来补充身份验证。这一层为应用程序增加了额外的安全级别。&lt;/li&gt;
&lt;li&gt;日志记录中间件：中间件可以用于日志记录目的，捕获每个请求和响应的有价值的信息。这有助于诊断问题，监控应用程序性能，分析用户行为。&lt;/li&gt;
&lt;li&gt;异常处理中间件：在任何应用程序中，错误和异常都是不可避免的。中间件便于集中处理异常，确保开发者可以实现自定义错误页面，记录详细的错误信息，并保持一致的用户体验。&lt;/li&gt;
&lt;li&gt;CORS中间件：跨源资源共享（CORS）是由中间件实现的一种安全特性，用于控制哪些域可以访问服务器上的资源。这对于保护Web应用程序和防止未经授权的访问至关重要。&lt;/li&gt;
&lt;li&gt;压缩中间件：为了提高性能，中间件可以用于在响应发送给客户端之前进行压缩。这减少了通过网络传输的数据量，从而使用户的加载时间更快。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;.NET Core中间件的优点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;模块化和可重用性：中间件通过允许开发者将特定功能封装到可重用的组件中，促进了模块化。这种模块化的方法简化了代码维护，并促进了在不同项目中重用中间件。&lt;/li&gt;
&lt;li&gt;管道定制：开发者可以根据他们的应用程序的特定需求，灵活地定制请求-响应管道。这种适应性对于定制应用程序的行为以满足独特的业务需求至关重要。&lt;/li&gt;
&lt;li&gt;改进的可测试性：中间件组件可以单独进行单元测试，提高了可测试性，并促进了测试驱动开发（TDD）实践的采用。这确保每个中间件组件都能正确地运行，并符合其预期的行为。&lt;/li&gt;
&lt;li&gt;集中配置：.NET Core中间件允许集中配置，使得管理和修改各种组件的行为变得更容易。这简化了调整应用程序设置的任务，无需修改代码。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;中间件的顺序重要吗？&lt;/h3&gt;
&lt;p&gt;是的，在ASP.NET Core中，将中间件组件添加到管道的顺序是重要的。中间件组件按照它们被添加到管道的顺序执行。这意味着中间件注册的顺序影响了它们在请求处理管道中的执行顺序。&lt;/p&gt;
&lt;p&gt;顺序之所以重要，是因为每个中间件组件可能会修改请求或响应，它们的执行顺序可能会影响最终的结果。如果你有身份验证中间件，它应该在依赖于经过身份验证的用户信息的其他中间件之前执行。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/2eff909df0d687103199dd1780d59f60.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;举例&lt;/h4&gt;
&lt;p&gt;在给定的场景中，客户端从&apos;https://d.domain.com&apos;源发起了一个请求，以访问服务内的一个端点。然而，在处理请求之前，负责验证跨源资源共享（CORS）策略的中间件进行了干预。在检查请求后，CORS中间件确定它并未符合定义的策略，因此拒绝了请求。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;异常信息&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&quot;对&apos;https://a-push.domain.com/notifyhub/negotiate&apos;的XMLHttpRequest的访问，源自&apos;https://d.domain.com&apos;，已被CORS策略阻止：预检请求的响应未通过访问控制检查：请求的资源上没有&apos;Access-Control-Allow-Origin&apos;头。&quot;[1][2][3]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/12126fc456cbd17c8403b581f86e5936.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;中间件处理&lt;/h3&gt;
&lt;h4&gt;中间件短路&lt;/h4&gt;
&lt;p&gt;短路是根据特定条件停止执行管道中的中间件组件并跳过其余组件的过程。这通常是为了提高性能或处理特定情况，而无需完全通过中间件管道。例如，你可能有一个中间件组件，它检查特定条件，如果条件满足，立即返回响应。在这个例子中，中间件处理请求并生成响应，而不调用其他中间件组件。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/e0fdd99407d83eb1e9094c685c77e5d0.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;注意事项&lt;/h4&gt;
&lt;p&gt;应谨慎应用短路，因为它可能会干扰执行序列和应用程序的预期行为。在决定中断中间件管道时，必须始终考虑特定的需求和可能的负面效果[4]。&lt;/p&gt;
&lt;h3&gt;中间件配置：理解Map、Use和Run方法&lt;/h3&gt;
&lt;p&gt;ASP.NET Core中间件提供了一种灵活的方式来处理应用程序管道中的请求和响应。Map、Use和Run三个关键方法在配置中间件组件中起着关键作用。让我们探讨每个方法，并理解它们如何贡献到请求处理管道[5]。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Map方法
Map方法用于根据请求的路径有条件地分支中间件管道。它允许你指定一条中间件分支来处理匹配特定路径前缀的请求[5]。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;app.Map(&quot;/path&quot;, builder =&amp;gt;
{
    builder.UseMiddleware1();
    builder.UseMiddleware2();
    // Additional middleware for the specified path
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在此示例中，如果请求路径以“/path”开头，则将执行 Map 块内指定的中间件。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use方法
Use方法是添加中间件组件到管道的基础构建块。它用于添加对所有请求或特定路径执行的中间件。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;app.Use(async (context, next) =&amp;gt;
{
    // Code to be executed before calling the next middleware
    await next();
    // Code to be executed after the next middleware has completed
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用Use方法添加的中间件按照在管道中注册的顺序执行。这对于需要对每个请求进行日志记录、身份验证或其他处理的任务来说至关重要。中间件组件按照它们被添加到管道的顺序执行，因此在添加中间件时应注意正确的顺序，否则应用程序可能无法按预期运行。这种排序对于安全性、性能和功能来说都至关重要。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Run方法
Run方法用于创建终止请求管道的终端中间件。它不调用管道中的下一个中间件，使其成为最后运行的中间件。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;app.Run(async context =&amp;gt;
{
    // Handle the request and generate a response
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run方法通常用于应该在管道中作为最终操作的任务，例如直接返回响应而不调用其他中间件。&lt;/p&gt;
&lt;p&gt;在ASP.NET Core中，Map、Use和Run方法为配置中间件和控制请求处理管道提供了强大的机制。通过了解这些方法的工作原理，我们可以为应用程序创建一个结构良好且高效的管道，以处理请求和响应处理的各个方面。&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-8.0&quot;&gt;https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-8.0&lt;/a&gt;
[2] &lt;a href=&quot;https://stackoverflow.com/questions/62728467/middleware-ordering&quot;&gt;https://stackoverflow.com/questions/62728467/middleware-ordering&lt;/a&gt;
[3] &lt;a href=&quot;https://www.c-sharpcorner.com/article/overview-of-middleware-in-asp-net-core/&quot;&gt;https://www.c-sharpcorner.com/article/overview-of-middleware-in-asp-net-core/&lt;/a&gt;
[4] &lt;a href=&quot;https://www.tutorialsteacher.com/core/aspnet-core-middleware&quot;&gt;https://www.tutorialsteacher.com/core/aspnet-core-middleware&lt;/a&gt;
[5] &lt;a href=&quot;https://subscription.packtpub.com/book/web-development/9781786463951/6/ch06lvl1sec47/order-of-middleware&quot;&gt;https://subscription.packtpub.com/book/web-development/9781786463951/6/ch06lvl1sec47/order-of-middleware&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 12 of learning English</title><link>https://blog.ithuo.net/posts/day-12-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-12-of-learning-english/</guid><pubDate>Tue, 12 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Sure, Derick. Here&apos;s your study plan for the fifth day of this week. This day, we&apos;ll focus on reinforcing your vocabulary and practicing the past continuous tense, and we&apos;ll introduce the future simple tense.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Morning Session: Vocabulary Review&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the words you learned over the past four days.&lt;/li&gt;
&lt;li&gt;Practice using these words in sentences and in conversation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Afternoon Session: Grammar - Future Simple Tense&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learn the structure of the future simple tense.&lt;/li&gt;
&lt;li&gt;Practice making sentences using the future simple tense, incorporating the words you&apos;ve learned over the week.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Evening Session: Listening and Speaking Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Listen to a simple English conversation or story. Try to identify the new words and the usage of the past continuous and future simple tenses.&lt;/li&gt;
&lt;li&gt;Practice speaking by retelling the story or conversation. Record your speech for self-assessment.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;End of Day Review&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the day&apos;s learning. Write down any questions or difficulties you encountered.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember, practice is key when learning a new language. Try to use the new words and grammar rules in your daily life. You can also use language learning apps or websites for additional practice.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://blog.cengage.com/tips-for-students-how-to-study-with-5-3-or-1-day-until-the-exam/&quot;&gt;https://blog.cengage.com/tips-for-students-how-to-study-with-5-3-or-1-day-until-the-exam/&lt;/a&gt;
[2] &lt;a href=&quot;https://www.unk.edu/offices/learning_commons/_files/finals-week/5%20Day%20Study%20Plan.pdf&quot;&gt;https://www.unk.edu/offices/learning_commons/_files/finals-week/5 Day Study Plan.pdf&lt;/a&gt;
[3] &lt;a href=&quot;https://asc.tamu.edu/study-learning-handouts/5-day-study-plan&quot;&gt;https://asc.tamu.edu/study-learning-handouts/5-day-study-plan&lt;/a&gt;
[4] &lt;a href=&quot;https://schoolhabits.com/the-ultimate-5-day-study-plan/&quot;&gt;https://schoolhabits.com/the-ultimate-5-day-study-plan/&lt;/a&gt;
[5] &lt;a href=&quot;https://www.intelligent.com/create-a-study-plan/&quot;&gt;https://www.intelligent.com/create-a-study-plan/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 11 of learning English</title><link>https://blog.ithuo.net/posts/day-11-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-11-of-learning-english/</guid><pubDate>Mon, 11 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Sure, Derick. Here&apos;s your study plan for the fourth day of this week. This day, we&apos;ll focus on further expanding your vocabulary and introducing the past continuous tense.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Morning Session: Vocabulary Building&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the words you learned the previous day.&lt;/li&gt;
&lt;li&gt;Learn 10 new words related to travel and transportation.&lt;/li&gt;
&lt;li&gt;Practice using these words in sentences.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Afternoon Session: Grammar - Past Continuous Tense&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learn the structure of the past continuous tense.&lt;/li&gt;
&lt;li&gt;Practice making sentences using the past continuous tense, incorporating the new words you learned in the morning session.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Evening Session: Listening and Speaking Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Listen to a simple English conversation or story. Try to identify the new words and the usage of the past continuous tense.&lt;/li&gt;
&lt;li&gt;Practice speaking by retelling the story or conversation. Record your speech for self-assessment.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;End of Day Review&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the day&apos;s learning. Write down any questions or difficulties you encountered.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember, practice is key when learning a new language. Try to use the new words and grammar rules in your daily life. You can also use language learning apps or websites for additional practice.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://blog.cengage.com/tips-for-students-how-to-study-with-5-3-or-1-day-until-the-exam/&quot;&gt;https://blog.cengage.com/tips-for-students-how-to-study-with-5-3-or-1-day-until-the-exam/&lt;/a&gt;
[2] &lt;a href=&quot;https://ou.edu/content/dam/UniversityCollege/Documents/SLC/5-Day-Study-Plan-4-Week-Courses.pdf&quot;&gt;https://ou.edu/content/dam/UniversityCollege/Documents/SLC/5-Day-Study-Plan-4-Week-Courses.pdf&lt;/a&gt;
[3] &lt;a href=&quot;https://www.intelligent.com/create-a-study-plan/&quot;&gt;https://www.intelligent.com/create-a-study-plan/&lt;/a&gt;
[4] &lt;a href=&quot;https://lsc.cornell.edu/how-to-study/studying-for-and-taking-exams/the-five-day-study-plan/&quot;&gt;https://lsc.cornell.edu/how-to-study/studying-for-and-taking-exams/the-five-day-study-plan/&lt;/a&gt;
[5] &lt;a href=&quot;https://blog.ecampus.com/3-day-study-plan/&quot;&gt;https://blog.ecampus.com/3-day-study-plan/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Ethereum Development With Rust 5</title><link>https://blog.ithuo.net/posts/ethereum-development-with-rust-5/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/ethereum-development-with-rust-5/</guid><pubDate>Mon, 11 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;:::note[提示]&lt;/p&gt;
&lt;p&gt;This series of articles mainly uses Rust&apos;s ethers-rs to reproduce the content of the book &quot;Ethereum Development with Go&quot;, so the title of this series is called &quot;Ethereum Development with Rust&quot;. Since the original book is already well-written, this series focuses more on replicating the code and will not explain too much of the related basic knowledge.&lt;/p&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;p&gt;This time, we will reproduce the fifth chapter on event logs and the sixth chapter on account signatures from &quot;Ethereum Development with Go&quot;.&lt;/p&gt;
&lt;p&gt;This chapter mainly includes the following content:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Subscribing to event logs&lt;/li&gt;
&lt;li&gt;Reading event logs&lt;/li&gt;
&lt;li&gt;Reading event logs of ERC-20 tokens&lt;/li&gt;
&lt;li&gt;Reading 0x Protocol event logs&lt;/li&gt;
&lt;li&gt;Generating and verifying signatures&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;pragma solidity &amp;gt;=0.9.0;

contract SimpleStorage {

    event ValueChanged(address indexed author, string oldValue, string newValue);

    string _value;

    constructor(string memory value) public {
        emit ValueChanged(msg.sender, _value, value);
        _value = value;
    }

    function getValue() view public returns (string memory) {
        return _value;
    }

    function setValue(string memory value) public {
        emit ValueChanged(msg.sender, _value, value);
        _value = value;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Subscribing to Event Logs&lt;/h3&gt;
&lt;p&gt;In addition to generating structs bound to contracts, the &lt;code&gt;abigen&lt;/code&gt; macro in &lt;code&gt;ethers-rs&lt;/code&gt; also generates a struct ending with Filter for each event, such as &lt;code&gt;ValueChangedFilter&lt;/code&gt; in the following text.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use ethers::prelude::*;
use ethers::types::Address;
use std::sync::Arc;

const RPC_URL: &amp;amp;str = &quot;ws://127.0.0.1:8546&quot;;

abigen!(
    SimpleContract,
    &quot;SimpleStorage.abi&quot;
);


#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;(), Box&amp;lt;dyn std::error::Error&amp;gt;&amp;gt; {
    let provider = Provider::&amp;lt;Ws&amp;gt;::connect(RPC_URL).await?;

    const CONTRACT_ADDRESS: &amp;amp;str = &quot;0x73511669fd4de447fed18bb79bafeac93ab7f31f&quot;;

    let contract_address: Address = CONTRACT_ADDRESS.parse()?;
    let client = Arc::new(provider);
    let contract = SimpleContract::new(contract_address, client);

    println!(&quot;合约设置的值: {:?}&quot;, contract.get_value().call().await?);
    let events = contract.events();
    let mut stream = events.stream().await?;

    println!(&quot;开始监听....&quot;);
    while let Some(Ok(evt)) = stream.next().await {
        println!(&quot;{evt:?}&quot;);
        // 因为只有一种类型的事件，match看起来有点鸡肋
        match evt {
            ValueChangedFilter { author, old_value, new_value } =&amp;gt; println!(&quot;{author:?} {old_value:?} {new_value:?}&quot;),
        }
    }

    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Reading Event Logs&lt;/h3&gt;
&lt;p&gt;Unlike &lt;code&gt;go-ethereum&lt;/code&gt;, &lt;code&gt;ethers-rs&lt;/code&gt; does not require additional processing. It can be used directly, just like the code above.&lt;/p&gt;
&lt;h3&gt;Reading Event Logs of ERC-20 Tokens&lt;/h3&gt;
&lt;p&gt;There is no essential difference between &lt;code&gt;ERC-20&lt;/code&gt; and ordinary events. The following two methods can be used for reference:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use ethers::{
    core::{
        abi::AbiDecode,
        types::{Address, Filter, U256},
    },
    providers::{Middleware, Provider, StreamExt, Ws},
};
use eyre::Result;
use std::sync::Arc;

const RPC_URL: &amp;amp;str = &quot;ws://127.0.0.1:8546&quot;;

#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;(), Box&amp;lt;dyn std::error::Error&amp;gt;&amp;gt; {
    let provider = Provider::&amp;lt;Ws&amp;gt;::connect(RPC_URL).await?;
    let client = Arc::new(provider);

    let erc20_transfer_filter =
        Filter::new().event(&quot;Transfer(address,address,uint256)&quot;);

    let mut stream = client.subscribe_logs(&amp;amp;erc20_transfer_filter).await?.take(2);

    println!(&quot;开始监听转账事件...&quot;);
    while let Some(log) = stream.next().await {
        println!(
            &quot;block: {:?}, tx: {:?}, token: {:?}, from: {:?}, to: {:?}, amount: {:?}&quot;,
            log.block_number,
            log.transaction_hash,
            log.address,
            Address::from(log.topics[1]),
            Address::from(log.topics[2]),
            U256::decode(log.data)
        );
    }

    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This method is relatively simple for a single event and does not require additional code generation using macros.&lt;/p&gt;
&lt;p&gt;The code below uses macros and is directly copied from the official examples.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use ethers::{
    contract::abigen,
    core::types::Address,
    providers::{Provider, StreamExt, Ws},
};
use eyre::Result;
use std::sync::Arc;

abigen!(
    IERC20,
    r#&quot;[
        event Transfer(address indexed from, address indexed to, uint256 value)
        event Approval(address indexed owner, address indexed spender, uint256 value)
    ]&quot;#,
);

const WSS_URL: &amp;amp;str = &quot;wss://mainnet.infura.io/ws/v3/c60b0bb42f8a4c6481ecd229eddaca27&quot;;
const WETH_ADDRESS: &amp;amp;str = &quot;0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2&quot;;

#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;()&amp;gt; {
    // 监听方法一般使用websocket协议
    let provider = Provider::&amp;lt;Ws&amp;gt;::connect(WSS_URL).await?;
    let client = Arc::new(provider);
    let address: Address = WETH_ADDRESS.parse()?;
    let contract = IERC20::new(address, client);

    listen_all_events(&amp;amp;contract).await?;
    listen_specific_events(&amp;amp;contract).await?;

    Ok(())
}

// 监听所有事件
async fn listen_all_events(contract: &amp;amp;IERC20&amp;lt;Provider&amp;lt;Ws&amp;gt;&amp;gt;) -&amp;gt; Result&amp;lt;()&amp;gt; {
    let events = contract.events().from_block(16232696);
    let mut stream = events.stream().await?.take(1);

    while let Some(Ok(evt)) = stream.next().await {
        match evt {
            IERC20Events::ApprovalFilter(f) =&amp;gt; println!(&quot;{f:?}&quot;),
            IERC20Events::TransferFilter(f) =&amp;gt; println!(&quot;{f:?}&quot;),
        }
    }

    Ok(())
}

/// 监听单一事件
async fn listen_specific_events(contract: &amp;amp;IERC20&amp;lt;Provider&amp;lt;Ws&amp;gt;&amp;gt;) -&amp;gt; Result&amp;lt;()&amp;gt; {
    let events = contract.event::&amp;lt;ApprovalFilter&amp;gt;().from_block(16232696);
    let mut stream = events.stream().await?.take(1);

    while let Some(Ok(f)) = stream.next().await {
        println!(&quot;ApprovalFilter event: {f:?}&quot;);
    }

    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Generate and verify signatures&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;use eyre::Result;
use ethers::core::rand::thread_rng;
use ethers::signers::{LocalWallet, Signer};

#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;()&amp;gt; {
    // 创建随机钱包
    let wallet = LocalWallet::new(&amp;amp;mut thread_rng());

    // 说明要签名的数据
    let message = &quot;Some data&quot;;

    // 生成签名对象
    let signature = wallet.sign_message(message).await?;
    println!(&quot;Produced signature {signature}&quot;);

    // 通过公钥验证
    signature.verify(message, wallet.address()).unwrap();
    println!(&quot;Verified signature produced by {:?}!&quot;, wallet.address());

    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Summary&lt;/h3&gt;
&lt;p&gt;At this point, I feel the code in this series is sufficient for Ethereum development (and also enough for me to come back and copy the code later), so I won&apos;t post the Rust implementation for &lt;code&gt;Swarm&lt;/code&gt; and &lt;code&gt;Whisper&lt;/code&gt; in the later parts. This series is complete.&lt;/p&gt;
&lt;p&gt;However, it&apos;s really sad that &lt;code&gt;ethers-rs&lt;/code&gt; is going to be deprecated.&lt;/p&gt;
&lt;p&gt;Reference Links&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://goethereumbook.org/zh/&quot;&gt;https://goethereumbook.org/zh/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://goethereumbook.org/en/&quot;&gt;https://goethereumbook.org/en/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ethereum.org/en/developers/docs/programming-languages/rust/#rust-projects-and-tools&quot;&gt;https://ethereum.org/en/developers/docs/programming-languages/rust/#rust-projects-and-tools&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gakonst.com/ethers-rs&quot;&gt;https://gakonst.com/ethers-rs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.ethers.org/v5/&quot;&gt;https://docs.ethers.org/v5/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 10 of learning English</title><link>https://blog.ithuo.net/posts/day-10-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-10-of-learning-english/</guid><pubDate>Sun, 10 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Absolutely, Derick. Here&apos;s a detailed study plan for the third day of this week:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Morning Session: Vocabulary Building&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start with a review of the words you learned the previous day.&lt;/li&gt;
&lt;li&gt;Learn 10 new words related to work and technology. Use flashcards, language learning apps, or a dictionary to understand the meaning, pronunciation, and usage of each word.&lt;/li&gt;
&lt;li&gt;Write sentences using each new word to understand its context.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Afternoon Session: Grammar - Past Simple Tense&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the structure of the past simple tense.&lt;/li&gt;
&lt;li&gt;Practice making sentences using the past simple tense. Try to incorporate the new words you learned in the morning session.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Evening Session: Listening and Speaking Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Listen to a simple English conversation or story. Try to identify the new words and the usage of the past simple tense.&lt;/li&gt;
&lt;li&gt;Practice speaking by retelling the story or conversation. Record your speech for self-assessment.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;End of Day Review&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the day&apos;s learning. Write down any questions or difficulties you encountered.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember, consistency is key in language learning. Try to immerse yourself in the language as much as possible. Listen to English songs, watch English movies or shows, and try to think in English. This will help you become more familiar with the language and improve your fluency.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://blog.cengage.com/tips-for-students-how-to-study-with-5-3-or-1-day-until-the-exam/&quot;&gt;https://blog.cengage.com/tips-for-students-how-to-study-with-5-3-or-1-day-until-the-exam/&lt;/a&gt;
[2] &lt;a href=&quot;https://www.intelligent.com/create-a-study-plan/&quot;&gt;https://www.intelligent.com/create-a-study-plan/&lt;/a&gt;
[3] &lt;a href=&quot;https://blog.ecampus.com/3-day-study-plan/&quot;&gt;https://blog.ecampus.com/3-day-study-plan/&lt;/a&gt;
[4] &lt;a href=&quot;https://algonquincollege.libguides.com/studyskills/weeklySchedule&quot;&gt;https://algonquincollege.libguides.com/studyskills/weeklySchedule&lt;/a&gt;
[5] &lt;a href=&quot;https://youtube.com/watch?v=C6JGBtnqWWU&quot;&gt;https://youtube.com/watch?v=C6JGBtnqWWU&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 9 of learning English</title><link>https://blog.ithuo.net/posts/day-9-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-9-of-learning-english/</guid><pubDate>Sat, 09 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Certainly, Derick. Here&apos;s a focused study plan for the second day of this week:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Morning Session: Grammar Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Begin with a quick review of the present simple tense from the previous day.&lt;/li&gt;
&lt;li&gt;Introduce and practice the present continuous tense, focusing on the difference between actions happening now and general routines.&lt;/li&gt;
&lt;li&gt;Write five sentences in the present simple tense and five in the present continuous tense.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Afternoon Session: Vocabulary Expansion&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learn 10 new words related to hobbies and leisure activities.&lt;/li&gt;
&lt;li&gt;Use each word in a sentence to practice context and usage.&lt;/li&gt;
&lt;li&gt;Engage in a vocabulary game or quiz to reinforce the new words.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Evening Session: Listening and Speaking&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Listen to an English podcast or watch a video related to technology or daily life, paying attention to the usage of the present simple and continuous tenses.&lt;/li&gt;
&lt;li&gt;Practice speaking by summarizing the content of the podcast or video, using the new vocabulary and grammar structures.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;End of Day Review&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the grammar and vocabulary covered today.&lt;/li&gt;
&lt;li&gt;Prepare any questions you have about the material for our next conversation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember to mark your study sessions on your calendar and adjust your plan as necessary to meet your weekly goals. Consistency and repetition are important, so try to use the new vocabulary and grammar rules throughout your day.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.intelligent.com/create-a-study-plan/&quot;&gt;https://www.intelligent.com/create-a-study-plan/&lt;/a&gt;
[2] &lt;a href=&quot;https://blog.cengage.com/tips-for-students-how-to-study-with-5-3-or-1-day-until-the-exam/&quot;&gt;https://blog.cengage.com/tips-for-students-how-to-study-with-5-3-or-1-day-until-the-exam/&lt;/a&gt;
[3] &lt;a href=&quot;https://www.wikihow.com/Study-a-Week-Before-an-Exam&quot;&gt;https://www.wikihow.com/Study-a-Week-Before-an-Exam&lt;/a&gt;
[4] &lt;a href=&quot;https://algonquincollege.libguides.com/studyskills/weeklySchedule&quot;&gt;https://algonquincollege.libguides.com/studyskills/weeklySchedule&lt;/a&gt;
[5] &lt;a href=&quot;https://www.wikihow.com/Study-in-One-Day&quot;&gt;https://www.wikihow.com/Study-in-One-Day&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 8 of learning English</title><link>https://blog.ithuo.net/posts/day-8-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-8-of-learning-english/</guid><pubDate>Fri, 08 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Derick. Here&apos;s your study plan for the second week. This week, we&apos;ll focus on expanding your vocabulary and introducing basic grammar rules.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Day 1: Vocabulary Building&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learn 20 new words related to everyday life (e.g., food, clothing, weather).&lt;/li&gt;
&lt;li&gt;Practice using these words in sentences.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Day 2: Basic Grammar - Present Simple Tense&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learn the structure of the present simple tense.&lt;/li&gt;
&lt;li&gt;Practice making sentences using the new grammar rule.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Day 3: Vocabulary Building&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learn 20 new words related to work and technology.&lt;/li&gt;
&lt;li&gt;Practice using these words in sentences.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Day 4: Basic Grammar - Past Simple Tense&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learn the structure of the past simple tense.&lt;/li&gt;
&lt;li&gt;Practice making sentences using the new grammar rule.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Day 5: Listening and Speaking Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Listen to a simple English conversation or story.&lt;/li&gt;
&lt;li&gt;Practice speaking by retelling the story or conversation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Day 6: Review&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the vocabulary and grammar rules learned this week.&lt;/li&gt;
&lt;li&gt;Practice speaking and writing sentences using the new words and grammar rules.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Day 7: Assessment&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Have a simple conversation with me about your daily life and work.&lt;/li&gt;
&lt;li&gt;I will assess your vocabulary usage, grammar, and fluency.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember, practice is key when learning a new language. Try to use the new words and grammar rules in your daily life. You can also use language learning apps or websites for additional practice.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Morning Session: Vocabulary Building&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start with a review of the words you learned the previous day.&lt;/li&gt;
&lt;li&gt;Learn 10 new words related to everyday life. Use flashcards, language learning apps, or a dictionary to understand the meaning, pronunciation, and usage of each word.&lt;/li&gt;
&lt;li&gt;Write sentences using each new word to understand its context.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Afternoon Session: Grammar - Present Simple Tense&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the structure of the present simple tense.&lt;/li&gt;
&lt;li&gt;Practice making sentences using the present simple tense. Try to incorporate the new words you learned in the morning session.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Evening Session: Practice and Review&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Listen to a simple English conversation or story. Try to identify the new words and the usage of the present simple tense.&lt;/li&gt;
&lt;li&gt;Practice speaking by retelling the story or conversation. Record your speech for self-assessment.&lt;/li&gt;
&lt;li&gt;Review the day&apos;s learning. Write down any questions or difficulties you encountered.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember, consistency is key in language learning. Try to immerse yourself in the language as much as possible. Listen to English songs, watch English movies or shows, and try to think in English. This will help you become more familiar with the language and improve your fluency.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.stetson.edu/administration/academic-success/media/STUDY%20SCHEDULE.pdf&quot;&gt;https://www.stetson.edu/administration/academic-success/media/STUDY SCHEDULE.pdf&lt;/a&gt;
[2] &lt;a href=&quot;https://www.intelligent.com/create-a-study-plan/&quot;&gt;https://www.intelligent.com/create-a-study-plan/&lt;/a&gt;
[3] &lt;a href=&quot;https://www.wikihow.com/Study-in-One-Day&quot;&gt;https://www.wikihow.com/Study-in-One-Day&lt;/a&gt;
[4] &lt;a href=&quot;https://blog.cengage.com/tips-for-students-how-to-study-with-5-3-or-1-day-until-the-exam/&quot;&gt;https://blog.cengage.com/tips-for-students-how-to-study-with-5-3-or-1-day-until-the-exam/&lt;/a&gt;
[5] &lt;a href=&quot;https://algonquincollege.libguides.com/studyskills/weeklySchedule&quot;&gt;https://algonquincollege.libguides.com/studyskills/weeklySchedule&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 7 of learning English</title><link>https://blog.ithuo.net/posts/day-7-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-7-of-learning-english/</guid><pubDate>Thu, 07 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hello Derick,&lt;/p&gt;
&lt;p&gt;Here&apos;s your study plan for the seventh day of the first week:&lt;/p&gt;
&lt;h3&gt;Day 7: Review and Practice&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Morning Session:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Begin with a comprehensive review of everything you&apos;ve learned this week: the alphabet, numbers, days of the week, basic greetings and phrases, common verbs and subjects, and basic adjectives.&lt;/li&gt;
&lt;li&gt;Use flashcards or notes to test your recall of vocabulary and phrases.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Afternoon Session:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Engage in listening and speaking practice. You can use language learning apps or online resources to listen to dialogues and repeat after them.&lt;/li&gt;
&lt;li&gt;Write down simple sentences or dialogues using the vocabulary and grammar you&apos;ve learned.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Evening Session:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Have a review session where you go over any areas you found challenging during the week.&lt;/li&gt;
&lt;li&gt;Prepare a few questions or topics for a conversation with me, focusing on the material covered this week.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification of Learning Results:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Self-Recording&lt;/strong&gt;: Record yourself speaking or having a simulated conversation to check your pronunciation and fluency.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Written Exercise&lt;/strong&gt;: Write a short paragraph using the vocabulary and grammar points you&apos;ve learned.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Live Conversation&lt;/strong&gt;: Have a conversation with me where you can apply what you&apos;ve learned in a real-life context.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.allencollege.edu/filesimages/Current%20Students/Academic%20Resources/5%20Day%20study%20plan.pdf&quot;&gt;https://www.allencollege.edu/filesimages/Current Students/Academic Resources/5 Day study plan.pdf&lt;/a&gt;
[2] &lt;a href=&quot;https://www.unk.edu/offices/learning_commons/_files/finals-week/5%20Day%20Study%20Plan.pdf&quot;&gt;https://www.unk.edu/offices/learning_commons/_files/finals-week/5 Day Study Plan.pdf&lt;/a&gt;
[3] &lt;a href=&quot;https://www.mtu.edu/success/academic/support/learning-centers/staying-on-track/pdfs/make-a-7-day-study-plan.pdf&quot;&gt;https://www.mtu.edu/success/academic/support/learning-centers/staying-on-track/pdfs/make-a-7-day-study-plan.pdf&lt;/a&gt;
[4] &lt;a href=&quot;https://success.oregonstate.edu/sites/success.oregonstate.edu/files/LearningCorner/Tools/7_day_study_plan_-_fill_-_20.pdf&quot;&gt;https://success.oregonstate.edu/sites/success.oregonstate.edu/files/LearningCorner/Tools/7_day_study_plan_-&lt;em&gt;fill&lt;/em&gt;-_20.pdf&lt;/a&gt;
[5] &lt;a href=&quot;https://www.intelligent.com/create-a-study-plan/&quot;&gt;https://www.intelligent.com/create-a-study-plan/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Ethereum Development With Rust 4</title><link>https://blog.ithuo.net/posts/ethereum-development-with-rust-4/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/ethereum-development-with-rust-4/</guid><pubDate>Thu, 07 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;:::note&lt;/p&gt;
&lt;p&gt;This series of articles mainly uses Rust&apos;s ethers-rs to reproduce the content of the book &quot;Ethereum Development with Go&quot;, so the title of this series is called &quot;Ethereum Development with Rust&quot;. Since the original book is already well-written, this series focuses more on replicating the code and will not explain too much of the related basic knowledge.&lt;/p&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;p&gt;This time, we will replicate the fourth chapter &quot;Smart Contracts&quot; from &quot;Ethereum Development with Go&quot;.&lt;/p&gt;
&lt;p&gt;The &quot;Smart Contracts&quot; chapter mainly includes the following content:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Compiling and ABI of Smart Contracts&lt;/li&gt;
&lt;li&gt;Deploying Smart Contracts&lt;/li&gt;
&lt;li&gt;Loading Smart Contracts&lt;/li&gt;
&lt;li&gt;Querying Smart Contracts&lt;/li&gt;
&lt;li&gt;Writing to Smart Contracts&lt;/li&gt;
&lt;li&gt;Reading the Bytecode of Smart Contracts&lt;/li&gt;
&lt;li&gt;Querying ERC20 Token Smart Contracts&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;pragma solidity &amp;gt;=0.9.0;

contract SimpleStorage {

    event ValueChanged(address indexed author, string oldValue, string newValue);

    string _value;

    constructor(string memory value) public {
        emit ValueChanged(msg.sender, _value, value);
        _value = value;
    }

    function getValue() view public returns (string memory) {
        return _value;
    }

    function setValue(string memory value) public {
        emit ValueChanged(msg.sender, _value, value);
        _value = value;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Compiling Smart Contracts and ABI&lt;/h3&gt;
&lt;p&gt;ethers-rs also requires a compiler to compile Solidity code. It looks for the &lt;code&gt;solc&lt;/code&gt; executable file in the executable path (on Windows, it&apos;s &lt;code&gt;solc.exe&lt;/code&gt;). If you want to specify the path to the &lt;code&gt;solc&lt;/code&gt; executable file, you can set the environment variable &lt;code&gt;SOLC_PATH&lt;/code&gt; to specify it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use ethers::{prelude::Abigen, solc::Solc};
use eyre::Result;

fn main() -&amp;gt; Result&amp;lt;()&amp;gt; {
    let mut args = std::env::args();
    args.next().unwrap(); // skip program name

    let contract_name = &quot;SimpleStorage&quot;;
    let contract: String = args
        .next()
        .unwrap_or_else(|| &quot;simple_contract.sol&quot;.to_owned());

    println!(&quot;生成合约{contract}的绑定对象\n&quot;);

    // ethers-rs的一些默认设定不太好改，比如evm的版本设置，如果需要设置的话，会麻烦很多
    let abi = if contract.ends_with(&quot;.sol&quot;) {
        let contracts = Solc::default().compile_source(&amp;amp;contract)?;
        let abi = contracts.get(&amp;amp;contract, &amp;amp;contract_name).unwrap().abi.unwrap();
        serde_json::to_string(abi).unwrap()
    } else {
        contract
    };


    let bindings = Abigen::new(&amp;amp;contract_name, abi)?.generate()?;
    // 如果第二个参数指定输出文件就输出到文件中.
    if let Some(output_path) = args.next() {
        bindings.write_to_file(output_path)?;
    } else {
        bindings.write(&amp;amp;mut std::io::stdout())?;
    }

    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output is a generated Rust version of the object, which can be used to interact with an Ethereum node. The output is as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pub use simple_storage::*;
/// This module was auto-generated with ethers-rs Abigen.
/// More information at: &amp;lt;https://github.com/gakonst/ethers-rs&amp;gt;
#[allow(
    clippy::enum_variant_names,
    clippy::too_many_arguments,
    clippy::upper_case_acronyms,
    clippy::type_complexity,
    dead_code,
    non_camel_case_types,
)]
pub mod simple_storage {
// 省略其他代码
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This file can be written to an &lt;code&gt;.rs&lt;/code&gt; file and then referenced in other code. However, this approach may not feel very user-friendly. Compared to this, I think generating an ABI file might be more suitable.&lt;/p&gt;
&lt;p&gt;You can use the following command to generate the corresponding ABI file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;solc --abi SimpleStorage.sol -o ./
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command uses the &lt;code&gt;solc&lt;/code&gt; compiler to generate the ABI file for the &lt;code&gt;SimpleStorage.sol&lt;/code&gt; contract and saves it in the current directory.&lt;/p&gt;
&lt;p&gt;The generated ABI file will have a name like &lt;code&gt;SimpleStorage.abi&lt;/code&gt; and will contain the JSON representation of the contract&apos;s ABI.&lt;/p&gt;
&lt;p&gt;Here&apos;s an example of how the generated ABI file might look:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[
  {
    &quot;inputs&quot;: [],
    &quot;name&quot;: &quot;getValue&quot;,
    &quot;outputs&quot;: [
      {
        &quot;internalType&quot;: &quot;uint256&quot;,
        &quot;name&quot;: &quot;&quot;,
        &quot;type&quot;: &quot;uint256&quot;
      }
    ],
    &quot;stateMutability&quot;: &quot;view&quot;,
    &quot;type&quot;: &quot;function&quot;
  },
  {
    &quot;inputs&quot;: [
      {
        &quot;internalType&quot;: &quot;uint256&quot;,
        &quot;name&quot;: &quot;value&quot;,
        &quot;type&quot;: &quot;uint256&quot;
      }
    ],
    &quot;name&quot;: &quot;setValue&quot;,
    &quot;outputs&quot;: [],
    &quot;stateMutability&quot;: &quot;nonpayable&quot;,
    &quot;type&quot;: &quot;function&quot;
  }
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The ABI file contains an array of objects, where each object represents a function or event of the contract. It includes information such as the function name, input parameters, output parameters, and the function&apos;s stateMutability.&lt;/p&gt;
&lt;p&gt;Having the ABI file separately allows you to easily load it into your Rust code using a JSON parsing library like &lt;code&gt;serde_json&lt;/code&gt;. You can then use the parsed ABI to create an instance of the contract and interact with it using the ethers-rs library.&lt;/p&gt;
&lt;p&gt;Using an ABI file provides more flexibility and modularity compared to directly embedding the generated Rust code in your project. It allows you to update the contract&apos;s ABI without modifying your Rust code, making it easier to manage and maintain your project.&lt;/p&gt;
&lt;h3&gt;Deploying Contracts&lt;/h3&gt;
&lt;p&gt;Similar to compiling contracts, deploying contracts also requires the corresponding Solidity compiler. In addition, there are requirements for the Ethereum node as well. The default EVM bytecode version generated by ethers-rs 2.0.10 is the Shanghai EVM version, so older Ethereum nodes may not work. The Geth node version I tested is v1.13.1.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use ethers::{
    contract::{abigen, ContractFactory},
    middleware::SignerMiddleware,
    providers::{Http, Provider, Middleware},
    signers::{Wallet, Signer},
    solc::Solc,
};
use eyre::Result;
use std::{convert::TryFrom, path::Path, sync::Arc};

// 生成类型安全的合约对象
abigen!(
    SimpleContract,
    &quot;simple_contract.json&quot;,
    event_derives(serde::Deserialize, serde::Serialize)
);

const RPC_URL: &amp;amp;str = &quot;http://127.0.0.1:8545&quot;;

#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;()&amp;gt; {
    let prikey = hex::decode(&quot;0xdf57089febbacf7ba0bc227dafbffa9fc08a93fdc68e1e42411a14efcf23656e&quot;).unwrap();
    let wallet = Wallet::from_bytes(&amp;amp;prikey).unwrap();
    println!(&quot;钱包私钥: {:?}&quot;, wallet.signer().to_bytes());
    println!(&quot;钱包公钥: {:?}&quot;, wallet.address());

    // 指定合约路径并编译
    let source = Path::new(&amp;amp;env!(&quot;CARGO_MANIFEST_DIR&quot;)).join(&quot;simple_contract.sol&quot;);
    let compiled = Solc::default().compile_source(source).expect(&quot;Could not compile contracts&quot;);
    // 获得编译之后的对象，因为solidity里面可以定义接口继承，所以需要使用find方法指定对应的合约名
    let (abi, bytecode, _runtime_bytecode) =
        compiled.find(&quot;SimpleStorage&quot;).expect(&quot;could not find contract&quot;).into_parts_or_default();


    // 3. 连接网络
    let provider = Provider::&amp;lt;Http&amp;gt;::try_from(RPC_URL)?;

    // 4. 因为部署合约需要写入数据到链上，所以需要使用钱包对象
    let chain_id = provider.get_chainid().await?.as_u64();
    let client = SignerMiddleware::new(provider, wallet.with_chain_id(chain_id));
    let client = Arc::new(client);

    // 5. 创建一个工厂对象，用于后续部署实例
    let factory = ContractFactory::new(abi, bytecode, client.clone());

    // 6. 部署的时候需要必要的初始值
    let contract = factory.deploy(&quot;initial value&quot;.to_string())?.send().await?;

    // 7. 获取合约部署后的地址
    let addr = contract.address();
    println!(&quot;contract is deployed at: {addr:?}&quot;);

    // 8. 创建与合约交互的合约对象
    let contract = SimpleContract::new(addr, client.clone());

    // 9.
    // 第一个await是等待交易返回PendingTransaction，第二个await是等待此交易被提交
    let _receipt = contract.set_value(&quot;hi&quot;.to_owned()).send().await?.await?;

    // 10. 获取所有事件
    let logs = contract.value_changed_filter().query().await?;

    // 11. 调用get_value方法
    let value = contract.get_value().call().await?;
    println!(&quot;Value: {value}. Logs: {}&quot;, serde_json::to_string(&amp;amp;logs)?);

    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Loading/Querying Smart Contracts&lt;/h3&gt;
&lt;p&gt;If we need to interact with an Ethereum node, we require the corresponding ABI. Therefore, we can use the previously compiled ABI file &lt;code&gt;SimpleStorage.abi&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use ethers::prelude::*;
use ethers::types::Address;
use std::sync::Arc;

const RPC_URL: &amp;amp;str = &quot;http://127.0.0.1:8545&quot;;

#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;(), Box&amp;lt;dyn std::error::Error&amp;gt;&amp;gt; {
    let provider = Provider::&amp;lt;Http&amp;gt;::try_from(RPC_URL)?;

    abigen!(
        SimpleContract,
        &quot;SimpleStorage.abi&quot;,
    );

    const CONTRACT_ADDRESS: &amp;amp;str = &quot;0x73511669fd4de447fed18bb79bafeac93ab7f31f&quot;;

    let contract_address: Address = CONTRACT_ADDRESS.parse()?;
    let client = Arc::new(provider);
    let contract = SimpleContract::new(contract_address, client);

    println!(&quot;合约设置的值: {:?}&quot;, contract.get_value().call().await?);

    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Write smart contract&lt;/h3&gt;
&lt;p&gt;The difference between writing and querying is that the former costs nothing and the latter costs money.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use ethers::prelude::*;
use ethers::types::Address;
use std::sync::Arc;

const RPC_URL: &amp;amp;str = &quot;http://127.0.0.1:8545&quot;;

#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;(), Box&amp;lt;dyn std::error::Error&amp;gt;&amp;gt; {
    let prikey = hex::decode(&quot;0xdf57089febbacf7ba0bc227dafbffa9fc08a93fdc68e1e42411a14efcf23656e&quot;).unwrap();
    let wallet = Wallet::from_bytes(&amp;amp;prikey).unwrap();
    // println!(&quot;钱包私钥: {:?}&quot;, wallet.signer().to_bytes());
    println!(&quot;钱包公钥: {:?}&quot;, wallet.address());

    let provider = Provider::&amp;lt;Http&amp;gt;::try_from(RPC_URL)?;

    abigen!(
        SimpleContract,
        &quot;SimpleStorage.abi&quot;,
    );

    const CONTRACT_ADDRESS: &amp;amp;str = &quot;0x73511669fd4de447fed18bb79bafeac93ab7f31f&quot;;

    let contract_address: Address = CONTRACT_ADDRESS.parse()?;
    let chain_id = provider.get_chainid().await?.as_u64();
    // contract对象实例化的时候需要一个ARC对象
    let signer =
        Arc::new(SignerMiddleware::new(provider, wallet.with_chain_id(chain_id)));

    let contract = SimpleContract::new(contract_address, signer);

    let _receipt = contract.set_value(&quot;new value&quot;.to_owned()).send().await?.await?;

    println!(&quot;合约新设置的值: {:?}&quot;, contract.get_value().call().await?);

    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Read the bytecode of the smart contract&lt;/h3&gt;
&lt;p&gt;Bytecode is the compiled data of code that requires specialized tools to debug visually.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use ethers::prelude::*;

const RPC_URL: &amp;amp;str = &quot;http://127.0.0.1:8545&quot;;

#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;(), Box&amp;lt;dyn std::error::Error&amp;gt;&amp;gt; {
    let provider = Provider::&amp;lt;Http&amp;gt;::try_from(RPC_URL)?;
    let code = provider.get_code(&quot;0x73511669fd4de447fed18bb79bafeac93ab7f31f&quot;, None).await?;
    println!(&quot;合约的合约代码: {:?}&quot;, code);
    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Query ERC20 token smart contract&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;use ethers::prelude::*;
use ethers::types::Address;
use ethers::utils;
use std::sync::Arc;

const RPC_URL: &amp;amp;str = &quot;http://127.0.0.1:8545&quot;;

#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;(), Box&amp;lt;dyn std::error::Error&amp;gt;&amp;gt; {
    let provider = Provider::&amp;lt;Http&amp;gt;::try_from(RPC_URL)?;

    let balance = provider.get_balance(&quot;0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199&quot;, None).await?;
    println!(&quot;balance: {} ether&quot;, utils::format_ether(balance));
    println!(&quot;balance: {balance:?} wei&quot;);

    abigen!(
        IERC20,
        r#&quot;[
            function totalSupply() external view returns (uint256)
            function balanceOf(address account) external view returns (uint256)
            function transfer(address recipient, uint256 amount) external returns (bool)
            function allowance(address owner, address spender) external view returns (uint256)
            function approve(address spender, uint256 amount) external returns (bool)
            function transferFrom( address sender, address recipient, uint256 amount) external returns (bool)
            event Transfer(address indexed from, address indexed to, uint256 value)
            event Approval(address indexed owner, address indexed spender, uint256 value)
        ]&quot;#,
    );

    const ERC20_CONTRACT_ADDRESS: &amp;amp;str = &quot;0xEB1774bc66930a417A76Df89885CeE7c1A29f405&quot;;

    let erc20_address: Address = ERC20_CONTRACT_ADDRESS.parse()?;
    let erc20_account_address: Address = &quot;0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199&quot;.parse()?;
    let client = Arc::new(provider);
    let contract = IERC20::new(erc20_address, client);

    if let Ok(total_supply) = contract.total_supply().call().await {
        println!(&quot;ERC20 total supply is {total_supply:?}&quot;);
    }

    if let Ok(balance) = contract.balance_of(erc20_account_address).call().await {
        println!(&quot;ERC20 total supply is {balance:?}&quot;);
    }

    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you need to read variables like symbol, decimals, etc., you need to use an ABI file.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use ethers::prelude::*;
use ethers::types::Address;
use ethers::utils;
use std::sync::Arc;

const RPC_URL: &amp;amp;str = &quot;http://127.0.0.1:8545&quot;;

#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;(), Box&amp;lt;dyn std::error::Error&amp;gt;&amp;gt; {
    let provider = Provider::&amp;lt;Http&amp;gt;::try_from(RPC_URL)?;

    let balance = provider.get_balance(&quot;0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199&quot;, None).await?;
    println!(&quot;balance: {} ether&quot;, utils::format_ether(balance));
    println!(&quot;balance: {balance:?} wei&quot;);

    abigen!(
        IERC20,
        &quot;IERC20.json&quot;,
    );

    const ERC20_CONTRACT_ADDRESS: &amp;amp;str = &quot;0x92B4FbB1Be8B98b00D643E485075186c3c61bae1&quot;;

    let erc20_address: Address = ERC20_CONTRACT_ADDRESS.parse()?;
    let erc20_account_address: Address = &quot;0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199&quot;.parse()?;
    let client = Arc::new(provider);
    let contract = IERC20::new(erc20_address, client);

    if let Ok(total_supply) = contract.total_supply().call().await {
        println!(&quot;ERC20 total supply is {total_supply:?}&quot;);
    }

    if let Ok(balance) = contract.balance_of(erc20_account_address).call().await {
        println!(&quot;ERC20 total supply is {balance:?}&quot;);
    }

    if let Ok(symbol) = contract.symbol().call().await {
        println!(&quot;ERC20 symbol is {symbol:?}&quot;);
    }

    if let Ok(decimals) = contract.decimals().call().await {
        println!(&quot;ERC20 decimals is {decimals:?}&quot;);
    }

    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can download the &lt;code&gt;IERC20.json&lt;/code&gt; file from &lt;a href=&quot;https://github.com/gakonst/ethers-rs/blob/master/examples/contracts/examples/abi/IERC20.json&quot;&gt;https://github.com/gakonst/ethers-rs/blob/master/examples/contracts/examples/abi/IERC20.json&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Summary&lt;/h3&gt;
&lt;p&gt;When developing off-chain, the most commonly written code is probably the code that interacts with contracts. The code for interacting with contracts is essentially similar, with the only difference being the methods and events exposed by different contracts. Therefore, it is necessary to know the corresponding contract&apos;s ABI for interaction.&lt;/p&gt;
&lt;p&gt;Reference Links&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://goethereumbook.org/zh/&quot;&gt;https://goethereumbook.org/zh/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://goethereumbook.org/en/&quot;&gt;https://goethereumbook.org/en/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ethereum.org/en/developers/docs/programming-languages/rust/#rust-projects-and-tools&quot;&gt;https://ethereum.org/en/developers/docs/programming-languages/rust/#rust-projects-and-tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gakonst.com/ethers-rs&quot;&gt;https://gakonst.com/ethers-rs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.ethers.org/v5/&quot;&gt;https://docs.ethers.org/v5/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Derick</author></item><item><title>Day 6 of learning English</title><link>https://blog.ithuo.net/posts/day-6-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-6-of-learning-english/</guid><pubDate>Wed, 06 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hello Derick,&lt;/p&gt;
&lt;p&gt;Sure, here&apos;s your study plan for the sixth day of the first week:&lt;/p&gt;
&lt;h3&gt;Day 6: Basic Adjectives and Descriptions&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Morning Session:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start with a quick review of the alphabet, sounds, basic greetings, numbers, days of the week, common verbs, subjects, and basic questions from the previous days.&lt;/li&gt;
&lt;li&gt;Learn basic adjectives such as &quot;big&quot;, &quot;small&quot;, &quot;happy&quot;, &quot;sad&quot;, &quot;good&quot;, and &quot;bad&quot;. Practice pronouncing each word and writing it down.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Afternoon Session:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learn how to use these adjectives to describe things. For example, &quot;The apple is big&quot;, &quot;I am happy&quot;.&lt;/li&gt;
&lt;li&gt;Practice using these adjectives in sentences and questions. For example, &quot;Is the apple big?&quot;, &quot;Are you happy?&quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Evening Session:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the adjectives and sentences by quizzing yourself or using flashcards.&lt;/li&gt;
&lt;li&gt;Write down the adjectives and sentences in order and try to use them in a conversation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification of Learning Results:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Self-Recording&lt;/strong&gt;: Record yourself saying the adjectives and sentences to check your pronunciation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Written Exercise&lt;/strong&gt;: Write down the adjectives and sentences from memory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practical Application&lt;/strong&gt;: Describe something around you using the adjectives you&apos;ve learned.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.allencollege.edu/filesimages/Current%20Students/Academic%20Resources/5%20Day%20study%20plan.pdf&quot;&gt;https://www.allencollege.edu/filesimages/Current Students/Academic Resources/5 Day study plan.pdf&lt;/a&gt;
[2] &lt;a href=&quot;https://www.unk.edu/offices/learning_commons/_files/finals-week/5%20Day%20Study%20Plan.pdf&quot;&gt;https://www.unk.edu/offices/learning_commons/_files/finals-week/5 Day Study Plan.pdf&lt;/a&gt;
[3] &lt;a href=&quot;https://www.intelligent.com/create-a-study-plan/&quot;&gt;https://www.intelligent.com/create-a-study-plan/&lt;/a&gt;
[4] &lt;a href=&quot;https://asc.tamu.edu/study-learning-handouts/5-day-study-plan&quot;&gt;https://asc.tamu.edu/study-learning-handouts/5-day-study-plan&lt;/a&gt;
[5] &lt;a href=&quot;https://blog.cengage.com/tips-for-students-how-to-study-with-5-3-or-1-day-until-the-exam/&quot;&gt;https://blog.cengage.com/tips-for-students-how-to-study-with-5-3-or-1-day-until-the-exam/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 5 of learning English</title><link>https://blog.ithuo.net/posts/day-5-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-5-of-learning-english/</guid><pubDate>Tue, 05 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hello Derick,&lt;/p&gt;
&lt;p&gt;Sure, here&apos;s your study plan for the fifth day of the first week:&lt;/p&gt;
&lt;h3&gt;Day 5: Basic Questions and Responses&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Morning Session:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start with a quick review of the alphabet, sounds, basic greetings, numbers, days of the week, common verbs, and subjects from the previous days.&lt;/li&gt;
&lt;li&gt;Learn basic question words such as &quot;who&quot;, &quot;what&quot;, &quot;where&quot;, &quot;when&quot;, &quot;why&quot;, and &quot;how&quot;. Practice pronouncing each word and writing it down.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Afternoon Session:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learn how to form basic questions using the question words and verbs you&apos;ve learned. For example, &quot;What is your name?&quot;, &quot;Where are you from?&quot;, &quot;How are you?&quot;.&lt;/li&gt;
&lt;li&gt;Practice responding to these questions. For example, &quot;My name is Derick&quot;, &quot;I am from China&quot;, &quot;I am good&quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Evening Session:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the question words, questions, and responses by quizzing yourself or using flashcards.&lt;/li&gt;
&lt;li&gt;Write down the questions and responses in order and try to use them in a conversation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification of Learning Results:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Self-Recording&lt;/strong&gt;: Record yourself asking and answering the questions to check your pronunciation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Written Exercise&lt;/strong&gt;: Write down the questions and responses from memory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practical Application&lt;/strong&gt;: Have a simple conversation with me using the questions and responses you&apos;ve learned.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.allencollege.edu/filesimages/Current%20Students/Academic%20Resources/5%20Day%20study%20plan.pdf&quot;&gt;https://www.allencollege.edu/filesimages/Current Students/Academic Resources/5 Day study plan.pdf&lt;/a&gt;
[2] &lt;a href=&quot;https://www.unk.edu/offices/learning_commons/_files/finals-week/5%20Day%20Study%20Plan.pdf&quot;&gt;https://www.unk.edu/offices/learning_commons/_files/finals-week/5 Day Study Plan.pdf&lt;/a&gt;
[3] &lt;a href=&quot;https://blog.cengage.com/tips-for-students-how-to-study-with-5-3-or-1-day-until-the-exam/&quot;&gt;https://blog.cengage.com/tips-for-students-how-to-study-with-5-3-or-1-day-until-the-exam/&lt;/a&gt;
[4] &lt;a href=&quot;https://asc.tamu.edu/study-learning-handouts/5-day-study-plan&quot;&gt;https://asc.tamu.edu/study-learning-handouts/5-day-study-plan&lt;/a&gt;
[5] &lt;a href=&quot;https://lsc.cornell.edu/how-to-study/studying-for-and-taking-exams/the-five-day-study-plan/&quot;&gt;https://lsc.cornell.edu/how-to-study/studying-for-and-taking-exams/the-five-day-study-plan/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 4 of learning English</title><link>https://blog.ithuo.net/posts/day-4-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-4-of-learning-english/</guid><pubDate>Mon, 04 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hello Derick,&lt;/p&gt;
&lt;p&gt;Absolutely! Here&apos;s your study plan for the fourth day of the first week:&lt;/p&gt;
&lt;h3&gt;Day 4: Common Verbs and Subjects&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Morning Session:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start with a quick review of the alphabet, sounds, basic greetings, numbers, and days of the week from the previous days.&lt;/li&gt;
&lt;li&gt;Learn common verbs such as &quot;be&quot;, &quot;have&quot;, &quot;do&quot;, and &quot;go&quot;. Practice pronouncing each verb and writing it down.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Afternoon Session:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learn the concept of subjects in English: &quot;I&quot;, &quot;you&quot;, &quot;he&quot;, &quot;she&quot;, &quot;it&quot;, &quot;we&quot;, &quot;they&quot;. Write them down and practice pronouncing them.&lt;/li&gt;
&lt;li&gt;Try to use the verbs and subjects in simple sentences, such as &quot;I am Derick&quot; or &quot;You are Judy&quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Evening Session:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the verbs and subjects by quizzing yourself or using flashcards.&lt;/li&gt;
&lt;li&gt;Write down the verbs and subjects in order and try to use them in sentences.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification of Learning Results:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Self-Recording&lt;/strong&gt;: Record yourself saying the verbs and subjects to check your pronunciation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Written Exercise&lt;/strong&gt;: Write down the verbs and subjects from memory and use them in sentences.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practical Application&lt;/strong&gt;: Tell me about yourself using the verbs and subjects you&apos;ve learned, such as &quot;I am Derick. I have a goal to learn English.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://blog.cengage.com/tips-for-students-how-to-study-with-5-3-or-1-day-until-the-exam/&quot;&gt;https://blog.cengage.com/tips-for-students-how-to-study-with-5-3-or-1-day-until-the-exam/&lt;/a&gt;
[2] &lt;a href=&quot;https://www.intelligent.com/create-a-study-plan/&quot;&gt;https://www.intelligent.com/create-a-study-plan/&lt;/a&gt;
[3] &lt;a href=&quot;https://www.vu.edu.au/about-vu/news-events/study-space/how-to-make-an-effective-study-plan&quot;&gt;https://www.vu.edu.au/about-vu/news-events/study-space/how-to-make-an-effective-study-plan&lt;/a&gt;
[4] &lt;a href=&quot;https://universityadvisement.byu.edu/3-step-study-plan&quot;&gt;https://universityadvisement.byu.edu/3-step-study-plan&lt;/a&gt;
[5] &lt;a href=&quot;https://www.fluentu.com/blog/english/english-study-plan/&quot;&gt;https://www.fluentu.com/blog/english/english-study-plan/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 3 of learning English</title><link>https://blog.ithuo.net/posts/day-3-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-3-of-learning-english/</guid><pubDate>Sun, 03 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hello Derick,&lt;/p&gt;
&lt;p&gt;Certainly! Here&apos;s your study plan for the third day of the first week:&lt;/p&gt;
&lt;h3&gt;Day 3: Numbers and Days of the Week&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Morning Session:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Begin with a quick review of the alphabet, sounds, and basic greetings from the previous days.&lt;/li&gt;
&lt;li&gt;Learn numbers 1-10 in English. Practice pronouncing each number several times.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Afternoon Session:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learn the days of the week: Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, and Sunday. Write them down and practice their pronunciation.&lt;/li&gt;
&lt;li&gt;Try to use the numbers and days in simple sentences, such as &quot;Today is Monday&quot; or &quot;I see three apples.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Evening Session:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the numbers and days of the week by quizzing yourself or using flashcards.&lt;/li&gt;
&lt;li&gt;Write down the days of the week in order and associate each day with an activity you do (e.g., &quot;On Monday, I study English&quot;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification of Learning Results:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Self-Recording&lt;/strong&gt;: Record yourself saying the numbers and days of the week to check your pronunciation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Written Exercise&lt;/strong&gt;: Write down the numbers and days from memory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Practical Application&lt;/strong&gt;: Tell me about your schedule using the days of the week and numbers, such as &quot;I have English class on Tuesday and Thursday.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Keep practicing these new words throughout the day, and don&apos;t hesitate to reach out if you have any questions. Good luck with your studies!&lt;/p&gt;
&lt;p&gt;For the third day of the first week, we will focus on two main topics: Numbers and Days of the Week. Here are the specific materials and activities for each topic:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Numbers 1-10&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;Materials: Flashcards with numbers 1-10 written on them, online videos or audio clips for pronunciation guidance.&lt;/li&gt;
&lt;li&gt;Activities: Practice pronouncing each number, use the numbers in simple sentences, and quiz yourself or have someone quiz you on the numbers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Days of the Week&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;Materials: Flashcards with the days of the week written on them, songs or rhymes that help memorize the days of the week, online videos or audio clips for pronunciation guidance.&lt;/li&gt;
&lt;li&gt;Activities: Practice pronouncing the days of the week, use the days in simple sentences (e.g., &quot;Today is Monday&quot;), and quiz yourself or have someone quiz you on the days of the week.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember, the goal is to familiarize yourself with these basic English words and be able to use them in simple sentences. Practice is key, so make sure to repeat the words and sentences several times throughout the day[1][2][3][4][5].&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.intelligent.com/create-a-study-plan/&quot;&gt;https://www.intelligent.com/create-a-study-plan/&lt;/a&gt;
[2] &lt;a href=&quot;https://blog.cengage.com/tips-for-students-how-to-study-with-5-3-or-1-day-until-the-exam/&quot;&gt;https://blog.cengage.com/tips-for-students-how-to-study-with-5-3-or-1-day-until-the-exam/&lt;/a&gt;
[3] &lt;a href=&quot;https://www.vu.edu.au/about-vu/news-events/study-space/how-to-make-an-effective-study-plan&quot;&gt;https://www.vu.edu.au/about-vu/news-events/study-space/how-to-make-an-effective-study-plan&lt;/a&gt;
[4] &lt;a href=&quot;https://universityadvisement.byu.edu/3-step-study-plan&quot;&gt;https://universityadvisement.byu.edu/3-step-study-plan&lt;/a&gt;
[5] &lt;a href=&quot;https://www.stetson.edu/administration/academic-success/media/STUDY%20SCHEDULE.pdf&quot;&gt;https://www.stetson.edu/administration/academic-success/media/STUDY SCHEDULE.pdf&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 2 of learning English</title><link>https://blog.ithuo.net/posts/day-2-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-2-of-learning-english/</guid><pubDate>Sat, 02 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hello Derick,&lt;/p&gt;
&lt;p&gt;Great job on completing Day 1! Now, let&apos;s move on to Day 2. Here&apos;s your plan:&lt;/p&gt;
&lt;h3&gt;Day 2: Basic Greetings and Phrases&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Morning Session:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start by reviewing the English alphabet and sounds you learned on Day 1.&lt;/li&gt;
&lt;li&gt;Next, learn basic English greetings such as &quot;Hello&quot;, &quot;Goodbye&quot;, &quot;Thank you&quot;, and &quot;Please&quot;. Practice saying these phrases out loud.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Afternoon Session:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Continue practicing the basic greetings. Try to use them in a conversation, even if it&apos;s just with yourself.&lt;/li&gt;
&lt;li&gt;Start learning some common English phrases like &quot;How are you?&quot;, &quot;Nice to meet you&quot;, and &quot;I&apos;m sorry&quot;. Practice these phrases out loud as well.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Evening Session:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the greetings and phrases you&apos;ve learned today.&lt;/li&gt;
&lt;li&gt;Write them down in a notebook and try to memorize them.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification of Learning Results:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Quiz&lt;/strong&gt;: At the end of the day, take a short quiz to test your knowledge of the greetings and phrases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pronunciation Check&lt;/strong&gt;: Record yourself saying the new words and phrases, and I will provide feedback.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conversation&lt;/strong&gt;: Try to use the new greetings and phrases in a conversation with me.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember, repetition is key when learning a new language. Practice these phrases as much as you can throughout the day. Good luck!&lt;/p&gt;
&lt;h3&gt;Day 2: Basic Greetings and Phrases&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Morning Session:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the English alphabet and sounds from Day 1 for about 15 minutes.&lt;/li&gt;
&lt;li&gt;Learn basic greetings: &quot;Hello&quot;, &quot;Goodbye&quot;, &quot;Thank you&quot;, &quot;Please&quot;, &quot;Good morning&quot;, &quot;Good afternoon&quot;, and &quot;Good evening&quot;. Write them down and practice pronouncing them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Afternoon Session:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Practice using the greetings you&apos;ve learned in different scenarios. For example, greeting someone in the morning with &quot;Good morning&quot; and saying &quot;Thank you&quot; when someone helps you.&lt;/li&gt;
&lt;li&gt;Learn how to introduce yourself with &quot;My name is...&quot; and ask someone&apos;s name with &quot;What is your name?&quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Evening Session:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Review the greetings and introduction phrases by practicing them with a partner or recording yourself and listening back.&lt;/li&gt;
&lt;li&gt;Memorize the phrases by writing them out and using flashcards.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Verification of Learning Results:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Self-Recording&lt;/strong&gt;: Record yourself saying the greetings and introduction phrases. Listen to the recordings to check your pronunciation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Written Exercise&lt;/strong&gt;: Write down the greetings and phrases from memory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Role-Playing&lt;/strong&gt;: Engage in a simple role-play where you greet me and introduce yourself, using the phrases you&apos;ve learned.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember to practice these phrases throughout the day in real-life situations or by simulating conversations. Consistent practice is essential for retention and improving your confidence in using the language. Good luck with Day 2!&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.uh.edu/ussc/launch/services/handouts/Handouts/Tips-On-Studying-A-Foreign-Language.pdf&quot;&gt;https://www.uh.edu/ussc/launch/services/handouts/Handouts/Tips-On-Studying-A-Foreign-Language.pdf&lt;/a&gt;
[2] &lt;a href=&quot;https://www.berlitz.com/blog/best-language-learning-methods&quot;&gt;https://www.berlitz.com/blog/best-language-learning-methods&lt;/a&gt;
[3] &lt;a href=&quot;https://universityadvisement.byu.edu/3-step-study-plan&quot;&gt;https://universityadvisement.byu.edu/3-step-study-plan&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>.NET 8 Blazor Snake Game</title><link>https://blog.ithuo.net/posts/net-8-blazor-snake-game/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/net-8-blazor-snake-game/</guid><pubDate>Sat, 02 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Mini Snake Game&lt;/h1&gt;
&lt;p&gt;贪吃蛇游戏是一款休闲益智类游戏，有 PC 和手机等多平台版本。既简单又好玩。该游戏通过控制蛇头方向吃蛋，从而使得蛇变得越来越长。&lt;/p&gt;
&lt;h3&gt;游戏板&lt;/h3&gt;
&lt;p&gt;在razor面板创建游戏界面&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;创建Snake.razor&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;game-container&quot;tabindex=&quot;0&quot;@onkeydown=&quot;ControlSnakeDirection&quot;&amp;gt;
    @for (int row = 0; row &amp;lt; NO_OF_ROWS; row++)
    {
        @for (int col = 0; col &amp;lt; N0_OF_COLS; col++)
        {
            bool isSnakeCell = IsSnakeCell(row, col);
            bool isSnakeHead = IsSnakeHead(row, col);
            bool isFoodCell = IsFoodCell(row, col);

            &amp;lt;divclass=&quot;cell @(isSnakeCell &amp;amp;&amp;amp; !isSnakeHead ? &quot;snake-body&quot;:&quot;&quot;)&quot;&amp;gt;
                @if (isSnakeCell)
                {
                    @if (isSnakeHead)
                    {
                        &amp;lt;span&amp;gt;🐲&amp;lt;/span&amp;gt;
                    }
                    else
                    {
                        &amp;lt;span&amp;gt;●&amp;lt;/span&amp;gt;
                    }
                }
                @if (isFoodCell)
                {
                    &amp;lt;span&amp;gt;🍎&amp;lt;/span&amp;gt;
                }
            &amp;lt;/div&amp;gt;
        }
    }
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;代码&lt;strong&gt;解释&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;在第 3 行，每次玩家按下键盘上的箭头键时，我们都会调用“&lt;code&gt;ControlSnakeDirection()&lt;/code&gt;”方法。此方法控制蛇响应用户输入的移动。但我们如何确定前进的方向呢？&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;我们有 &lt;code&gt;Direction&lt;/code&gt; 枚举，这是一种表示蛇的运动选项的简洁方式。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;public enum Direction
    {
        UP = 0,
        RIGHT = 1,
        DOWN = 2,
        LEFT = 3
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;接下来，在第 4 行和第 6 行，我们使用两个嵌套循环来构建游戏板，有效地将页面划分为 15x15 部分的网格。循环变量由静态类 &lt;code&gt;GameHelper&lt;/code&gt; 填充，该静态类保存与游戏相关的基本信息。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;public static class GameHelper
	{
		public const int NO_OF_ROWS = 15;
		public const int N0_OF_COLS = 15;
       public const int SNAKE_SPEED = 600;
   }
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;通过这三种方法，我们的游戏变得生动起来。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;IsSnakeCell(row, col)&lt;/code&gt;：检查给定行和列坐标处的当前单元格是否属于蛇的身体。它返回一个布尔值，表明该细胞是否是蛇身体的一部分。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;IsSnakeHead(row, col)&lt;/code&gt;：与上一个方法类似，该方法验证当前单元格是否代表蛇的头。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;IsFoodCell(row, col)&lt;/code&gt;：该方法检测当前单元格是否包含美味的苹果🍎。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;棋盘上的每个单元格都被分配了一个用途 - 它要么是蛇的头 (🐲)、蛇的身体 (●)、诱人的苹果 (🍎) 或空单元格。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我们应用于每个单元格的 CSS 类不仅仅是样式 - 它们是让我们的游戏栩栩如生的视觉提示。如果一个单元格属于蛇的身体（但不是头部），我们给它“&lt;code&gt;snake-body&lt;/code&gt;”类，并用绿色背景绘制它。同时，“&lt;code&gt;cell&lt;/code&gt;”类应用于每个单元格，从而产生填充板上的那些迷人的框。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;cell @(isSnakeCell &amp;amp;&amp;amp; !isSnakeHead ? &quot;snake-body&quot; : &quot;&quot;)&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;4.1. 如果“&lt;code&gt;isSnakeHead&lt;/code&gt;”为 &lt;code&gt;true&lt;/code&gt;，则显示蛇头的龙表情符号 (🐲) 或蛇身体的点 (●)。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@if(isSnakeCell)
{
    @if(isSnakeHead)
    {
        &amp;lt; span &amp;gt;☃️&amp;lt;/ span &amp;gt;
    }
    else
    {
       &amp;lt; span &amp;gt;🐧&amp;lt;/ span &amp;gt;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;4.2. 如果 &lt;code&gt;isFoodCell&lt;/code&gt; 为 &lt;code&gt;true&lt;/code&gt;，它会显示一个苹果表情符号 🍎 来代表食物。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@if (isFoodCell)
{
    &amp;lt;span&amp;gt;🍎&amp;lt;/span&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;记录分数&lt;/h3&gt;
&lt;p&gt;如果没有办法跟踪您的进度，游戏就不算完整。 “&lt;code&gt;CurrentScore&lt;/code&gt;”和“&lt;code&gt;TopScore&lt;/code&gt;”字段位于屏幕顶部，为您提供实时跟踪。&lt;/p&gt;
&lt;p&gt;为了管理分数，我们引入了包含两个基本字段的 &lt;code&gt;Score&lt;/code&gt; 类。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;CurrentScore&lt;/code&gt;：随着您累积积分，此字段会在整个游戏过程中更新。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TopScore&lt;/code&gt;：最高成就，该字段记录您在游戏中取得的最高分。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;游戏成绩&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class Score
{
    public int CurrentScore;
    public int TopScore;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;逻辑：Blazor.razor.cs 背后的代码&lt;/h3&gt;
&lt;p&gt;在幕后的 &lt;code&gt;Blazor.razor.cs&lt;/code&gt; 文件中，隐藏着我们游戏的核心——控制蛇的每一个动作、管理游戏状态并处理用户输入的逻辑。&lt;/p&gt;
&lt;h3&gt;字段和属性&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;currentCell&lt;/code&gt;：该字段表示蛇在游戏板上的当前位置，存储为具有行和列坐标的 &lt;code&gt;SnakeCell&lt;/code&gt; 类的实例。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SnakeBody&lt;/code&gt;：一个列表，记录了蛇身体所占据的每个单元格的位置。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Score&lt;/code&gt;：前面介绍的 &lt;code&gt;Score&lt;/code&gt; 类的实例，包含 &lt;code&gt;CurrentScore&lt;/code&gt; 和 &lt;code&gt;TopScore&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isGameOver&lt;/code&gt;：一个布尔标志，用于监视游戏是否已结束或仍在进行中。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SnakeDirection&lt;/code&gt;：一个枚举字段（Direction），保留蛇当前的移动方向 - 向上、向右、向下或向左。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;foodRow&lt;/code&gt; 和 &lt;code&gt;foodCol&lt;/code&gt;：整数字段，用于精确定位食物在游戏板上的当前位置。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;public class SnakeCell
{
    public int Row { get; set; }

    public int Col { get; set; }
}

public partial class Snake
{
      SnakeCell currentCell;

      readonly List&amp;lt;SnakeCell&amp;gt; snakeBody = new();

      Score score = new();

      bool isGameOver;

      // Define the Snake&apos;s initial direction
      Direction snakeDirection = Direction.RIGHT;

      // Define the food&apos;s initial position
      int foodRow = 5;
      int foodCol = 5;

}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;初始化和游戏循环&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;OnInitializedAsync()&lt;/code&gt;：当组件首次初始化时会触发此方法。它通过初始化基本参数并通过 StartGame 方法启动游戏循环来为我们的游戏奠定基础。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;protected override async Task OnInitializedAsync()
{
    InitializeGame();
    await StartGame();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;InitializeGame()&lt;/code&gt;：游戏参数的摇篮！这种方法产生了一些基本元素，例如蛇的起始位置、得分，当然还有食物的位置。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;private void InitializeGame()
{
    // Define the Snake&apos;s initial position
    currentCell = new() { Row = 10, Col = 10 };

    // Initialize the snake&apos;s size to 1
    score.CurrentScore = 1;

    // Initialize the snake&apos;s body with one cell at the starting position
    snakeBody.Add(CloneSnakeCell());

    // Generate the initial food
    GenerateFood();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;StartGame()&lt;/code&gt;：一个不断更新游戏状态的异步动力源。它控制蛇的移动，检查碰撞，并不知疲倦地奔跑，直到游戏结束。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;private async Task StartGame()
{
    // Start the game loop
    while (!isGameOver)
    {
        UpdateSnakeDirection();
        if (IsFoodFound())
        {
            score.CurrentScore++;
            GenerateFood();
        }
        await Task.Delay(SNAKE_SPEED);
        StateHasChanged();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;游戏逻辑&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ControlSnakeDirection()&lt;/code&gt;：一种处理用户输入的方法，确保蛇根据箭头键按下适当地改变方向。如果您还记得清单 1，我们会在 &lt;strong&gt;@KeyDown&lt;/strong&gt; 事件上调用此方法。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;private void ControlSnakeDirection(KeyboardEventArgs e)
{
    switch (e.Key)
    {
        case &quot;ArrowUp&quot;:

            snakeDirection = Direction.UP;
            break;
        case &quot;ArrowRight&quot;:

            snakeDirection = Direction.RIGHT;
            break;
        case &quot;ArrowDown&quot;:

            snakeDirection = Direction.DOWN;
            break;
        case &quot;ArrowLeft&quot;:

            snakeDirection = Direction.LEFT;
            break;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;UpdateSnakeDirection()&lt;/code&gt;：这个方法是我们游戏的引擎，根据蛇的当前方向管理蛇的位置更新。然后增加蛇的大小，并检查游戏是否结束。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;private void UpdateSnakeDirection()
{
    switch (snakeDirection)
    {
        case Direction.UP:
            currentCell.Row--;
            break;
        case Direction.RIGHT:
            currentCell.Col++;
            break;
        case Direction.DOWN:
            currentCell.Row++;
            break;
        case Direction.LEFT:
            currentCell.Col--;
            break;
    }

    // Add the new current Cell to the  of the snake&apos;s body
    snakeBody.Insert(0, CloneSnakeCell());

    //Check if Game is over
    IsGameOver();

    // Remove the last cell (tail) to maintain the snake&apos;s size
    if (snakeBody.Count &amp;gt; score.CurrentScore)
    {
        snakeBody.RemoveAt(snakeBody.Count - 1);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;IsGameOver()&lt;/code&gt;：游戏结束条件的守护者！它会监视与游戏板边界的碰撞，并为玩家提供重置游戏或探索我的网站 https://rikampalkar.github.io 的选择。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;private async Task IsGameOver()
{
    if (currentCell.Row &amp;lt; 0 || currentCell.Row &amp;gt;= NO_OF_ROWS || currentCell.Col &amp;lt; 0 || currentCell.Col &amp;gt;= N0_OF_COLS)
    {
        isGameOver = true;
        bool isResetGame = await js.InvokeAsync&amp;lt;bool&amp;gt;(&quot;ResetGamePopup&quot;, score.CurrentScore);
        if (isResetGame)
        {
            if (score.CurrentScore &amp;gt; score.TopScore)
            {
                score.TopScore = score.CurrentScore;
            }
            ResetGame();
        }
        else
        {
            await js.InvokeVoidAsync(&quot;navigateToWebsite&quot;, $&quot;https://rikampalkar.github.io/&quot;);
        }
    }
    isGameOver = false;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;ResetGame()&lt;/code&gt;：当玩家决定重新开始时，此方法负责为新的游戏会话清除记录。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;private void ResetGame()
{
    snakeBody.Clear();
    isGameOver = false;
    OnInitializedAsync();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;GenerateFood()&lt;/code&gt;：幕后主厨！此功能会在游戏板上的随机位置烹制一批新食物。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;private void GenerateFood()
{
    var random = new Random();
    foodRow = random.Next(0, NO_OF_ROWS);
    foodCol = random.Next(0, N0_OF_COLS);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;CloneSnakeCell()&lt;/code&gt;：此方法克隆当前细胞的位置，作为蛇体细胞的蓝图。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;private SnakeCell CloneSnakeCell()
{
     return new SnakeCell() { Row = currentCell.Row, Col= currentCell.Col };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;CSS 方法&lt;/h3&gt;
&lt;p&gt;如果没有通过这些私有方法为您带来的视觉效果，我们的游戏将是不完整的。他们决定细胞在游戏板上的显示方式，确保蛇身、蛇头和食物恰到好处地突出。通过这些私有方法与razorUI通信&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;//This method checks whether the cell at the given row and col coordinates belongs to the snake&apos;s body.
private bool IsSnakeCell(int row, int col)
{
    return snakeBody.Exists(cell =&amp;gt; cell.Row == row &amp;amp;&amp;amp; cell.Col == col);
}

//This method checks whether the cell at the given row and col coordinates matches the position of the food
private bool IsFoodCell(int row, int col)
{
     return row == foodRow &amp;amp;&amp;amp; col == foodCol;
}

// Function to check if a cell is the snake head
private bool IsSnakeHead(int row, int col)
{
      return row == snakeBody[0].Row &amp;amp;&amp;amp; col == snakeBody[0].Col;
}

// Check for collision between the Snake and food
private bool IsFoodFound()
{
      return currentCell.Row == foodRow &amp;amp;&amp;amp; currentCell.Col == foodCol;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;源代码&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/DerickIT/moni-blazorwasm-.net8-hack&quot;&gt;link_preview&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Day 1 of learning English</title><link>https://blog.ithuo.net/posts/day-1-of-learning-english/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/day-1-of-learning-english/</guid><pubDate>Fri, 01 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Effective study techniques for learning a new language include:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Daily Study&lt;/strong&gt;: Consistency is key in language learning. Schedule daily study periods and stick to them[1].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Active Practice&lt;/strong&gt;: Practice speaking and writing in the language regularly. This can be done through conversation practice, writing exercises, or even speaking to yourself[1][2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Immerse Yourself&lt;/strong&gt;: Try to make the language a part of your daily life. This could involve watching TV shows, listening to podcasts, or reading books in the language you&apos;re learning[2][3].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use Spaced Repetition&lt;/strong&gt;: This technique involves reviewing information at increasing intervals over time, which is particularly effective for vocabulary acquisition[2].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transcription Technique&lt;/strong&gt;: This involves listening to a piece of language and then writing down what you hear. It&apos;s a great way to improve your listening skills and understanding of the language[3].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rote Memorization&lt;/strong&gt;: This involves repeating information until it is memorized. It can be particularly useful for learning vocabulary and basic phrases[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Peer-to-Peer Learning&lt;/strong&gt;: Practice with a partner or a language exchange group. This provides opportunities to use the language in a conversational context[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use Language Learning Apps&lt;/strong&gt;: Apps like Duolingo, Babbel, or Rosetta Stone can provide structured learning paths and interactive exercises[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Set Clear Goals&lt;/strong&gt;: Having clear, achievable goals can help keep you motivated and give you a sense of progress[4].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Listen Regularly&lt;/strong&gt;: Regular exposure to the language, especially through listening, can help improve your understanding and pronunciation[2][5].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember, everyone learns differently, so it&apos;s important to find the methods that work best for you.&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.uh.edu/ussc/launch/services/handouts/Handouts/Tips-On-Studying-A-Foreign-Language.pdf&quot;&gt;https://www.uh.edu/ussc/launch/services/handouts/Handouts/Tips-On-Studying-A-Foreign-Language.pdf&lt;/a&gt;
[2] &lt;a href=&quot;https://mangolanguages.com/resources-articles/the-most-effective-language-learning-strategies/&quot;&gt;https://mangolanguages.com/resources-articles/the-most-effective-language-learning-strategies/&lt;/a&gt;
[3] &lt;a href=&quot;https://www.berlitz.com/blog/best-language-learning-methods&quot;&gt;https://www.berlitz.com/blog/best-language-learning-methods&lt;/a&gt;
[4] &lt;a href=&quot;https://gurmentor.com/techniques-for-learning-a-foreign-language/&quot;&gt;https://gurmentor.com/techniques-for-learning-a-foreign-language/&lt;/a&gt;
[5] &lt;a href=&quot;https://www.reddit.com/r/languagelearning/comments/n4z9bz/what_are_the_5_top_tips_for_learning_a_language/?rdt=51048&quot;&gt;https://www.reddit.com/r/languagelearning/comments/n4z9bz/what_are_the_5_top_tips_for_learning_a_language/?rdt=51048&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>English learning plan</title><link>https://blog.ithuo.net/posts/english-learning-plan/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/english-learning-plan/</guid><pubDate>Fri, 01 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Based on your goal of reaching conversational English proficiency in 3 months, here&apos;s a detailed weekly study plan:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Weeks 1-2: Introduction to English&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Focus: Alphabet, basic vocabulary, and simple phrases.&lt;/li&gt;
&lt;li&gt;Activities: Use language learning apps like Duolingo or Rosetta Stone for 1 hour daily. Practice writing the alphabet and simple words.&lt;/li&gt;
&lt;li&gt;Verification: Write a short self-introduction in English.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Weeks 3-4: Basic Grammar&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Focus: Basic sentence structure, present tense verbs, articles, and prepositions.&lt;/li&gt;
&lt;li&gt;Activities: Continue using language learning apps. Start reading simple English texts like children&apos;s books.&lt;/li&gt;
&lt;li&gt;Verification: Write simple sentences about your daily routine.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Weeks 5-6: Expanding Vocabulary and Grammar&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Focus: Past tense verbs, adjectives, and adverbs.&lt;/li&gt;
&lt;li&gt;Activities: Start watching English language children&apos;s shows or cartoons. Continue reading and expand to more complex texts.&lt;/li&gt;
&lt;li&gt;Verification: Write a short story about a past event.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Weeks 7-8: Intermediate Grammar&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Focus: Future tense, conditional sentences, and conjunctions.&lt;/li&gt;
&lt;li&gt;Activities: Start listening to English language podcasts or music. Try to have simple conversations in English.&lt;/li&gt;
&lt;li&gt;Verification: Write a plan for a future event or goal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Weeks 9-10: Conversational Skills&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Focus: Idiomatic expressions, phrasal verbs, and colloquial language.&lt;/li&gt;
&lt;li&gt;Activities: Start watching English movies or TV shows with subtitles. Try to participate in English language forums or chat groups.&lt;/li&gt;
&lt;li&gt;Verification: Have a conversation in English about a movie or TV show you watched.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Weeks 11-12: Advanced Conversational Skills&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Focus: Technical vocabulary related to software technology, nuanced expressions, and complex sentence structures.&lt;/li&gt;
&lt;li&gt;Activities: Read articles or books related to software technology. Try to explain technical concepts in English.&lt;/li&gt;
&lt;li&gt;Verification: Have a conversation in English about a technical topic in software technology.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember, language learning requires consistent practice. Try to immerse yourself in English as much as possible by changing your phone or computer language to English, labeling items around your house in English, and thinking in English. Good luck![1][2][3][4]&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://zhuanlan.zhihu.com/p/661734486?utm_id=0&quot;&gt;https://zhuanlan.zhihu.com/p/661734486?utm_id=0&lt;/a&gt;
[2] &lt;a href=&quot;https://github.com/PlexPt/awesome-chatgpt-prompts-zh&quot;&gt;https://github.com/PlexPt/awesome-chatgpt-prompts-zh&lt;/a&gt;
[3] &lt;a href=&quot;https://cloud.tencent.com/developer/article/2248752&quot;&gt;https://cloud.tencent.com/developer/article/2248752&lt;/a&gt;
[4] &lt;a href=&quot;https://query.libretexts.org/%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87/%E5%9B%BE%E4%B9%A6%EF%BC%9A%E5%A4%A7%E5%AD%A6%E6%88%90%E5%8A%9F_(OpenStax)/12:_%E8%A7%84%E5%88%92%E4%BD%A0%E7%9A%84%E6%9C%AA%E6%9D%A5/12.02:_12.2%EF%BC%9A%E4%BD%A0%E7%9A%84%E6%88%90%E5%8A%9F%E4%B9%8B%E8%B7%AF%E2%80%94%E2%80%94%E8%81%8C%E4%B8%9A%E8%A7%84%E5%88%92%E5%91%A8%E6%9C%9F&quot;&gt;https://query.libretexts.org/简体中文/图书：大学成功_(OpenStax)/12:_规划你的未来/12.02:_12.2：你的成功之路——职业规划周期&lt;/a&gt;
[5] &lt;a href=&quot;https://zhuanlan.zhihu.com/p/446189034?utm_id=0&quot;&gt;https://zhuanlan.zhihu.com/p/446189034?utm_id=0&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Ethereum Development With Rust 3</title><link>https://blog.ithuo.net/posts/ethereum-development-with-rust-3/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/ethereum-development-with-rust-3/</guid><pubDate>Sun, 19 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;:::note&lt;/p&gt;
&lt;p&gt;This series of articles mainly uses Rust&apos;s &lt;code&gt;ethers-rs&lt;/code&gt; to replicate the content of the book &quot;Ethereum Development with Go&quot;. Therefore, the title of this series is called &quot;Ethereum Development with Rust&quot;. It can be considered as a quick start tutorial for &lt;code&gt;ethers-rs&lt;/code&gt;. Since the original book is already well-written, this series will focus more on replicating the code and will not explain too much about the related basic knowledge.&lt;/p&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;p&gt;This time, we will replicate the third chapter &quot;Transactions&quot; from &quot;Ethereum Development with Go&quot;.&lt;/p&gt;
&lt;p&gt;The &quot;Transactions&quot; chapter mainly includes the following content:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Querying blocks&lt;/li&gt;
&lt;li&gt;Querying transactions&lt;/li&gt;
&lt;li&gt;ETH transfer&lt;/li&gt;
&lt;li&gt;Token transfer&lt;/li&gt;
&lt;li&gt;Listening for new blocks&lt;/li&gt;
&lt;li&gt;Creating raw transactions&lt;/li&gt;
&lt;li&gt;Sending raw transactions&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The following dependencies are used in this article:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ethers = {version=&quot;2.0&quot;, features=[&quot;rustls&quot;, &quot;ws&quot;]}
tokio = {version=&quot;1&quot;, features=[&quot;full&quot;]}
eyre = &quot;0.6&quot;
hex = { package = &quot;const-hex&quot;, version = &quot;1.6&quot;, features = [&quot;hex&quot;] }
regex = &quot;1.10.2&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Query block&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ethers-rs&lt;/code&gt; does not provide a way to get the block header, so just get the corresponding block.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use ethers::prelude::*;

const RPC_URL: &amp;amp;str = &quot;http://127.0.0.1:8545&quot;;

#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;(), Box&amp;lt;dyn std::error::Error&amp;gt;&amp;gt; {
    let provider = Provider::&amp;lt;Http&amp;gt;::try_from(RPC_URL)?;

    let block = provider.get_block(1).await?.unwrap();

    println!(&quot;{:?}&quot;, block.number);
    println!(&quot;{:?}&quot;, block.time().unwrap());
    println!(&quot;{:?}&quot;, block.timestamp);
    println!(&quot;{:?}&quot;, block.difficulty);
    println!(&quot;{:?}&quot;, block.hash.unwrap());
    println!(&quot;{:?}&quot;, block.transactions.len());
    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Query transaction&lt;/h3&gt;
&lt;p&gt;Unlike &lt;code&gt;go-ethereum&lt;/code&gt;, the transaction object of &lt;code&gt;ethers-rs&lt;/code&gt; does not need to construct its own signature object to decode the data to obtain the &lt;code&gt;from&lt;/code&gt; field.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use ethers::prelude::*;

const RPC_URL: &amp;amp;str = &quot;http://127.0.0.1:8545&quot;;

#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;(), Box&amp;lt;dyn std::error::Error&amp;gt;&amp;gt; {
    let provider = Provider::&amp;lt;Http&amp;gt;::try_from(RPC_URL)?;

    let block = provider.get_block_with_txs(1).await?.unwrap();
    for tx in block.transactions {
        println!(&quot;{:?}&quot;, tx.hash);
        println!(&quot;{:?}&quot;, tx.value);
        println!(&quot;{:?}&quot;, tx.gas);
        println!(&quot;{:?}&quot;, tx.gas_price.unwrap());
        println!(&quot;{:?}&quot;, tx.nonce);
        println!(&quot;{:?}&quot;, tx.input);
        // to可能为None, 因为创建合约的交易没有to字段
        println!(&quot;{:?}&quot;, tx.to.unwrap());
        println!(&quot;{:?}&quot;, tx.from);

        let recipt = provider.get_transaction_receipt(tx.hash).await?.unwrap();
        println!(&quot;{:?}&quot;, recipt.status.unwrap());
    }


    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ETH transfer&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ethers-rs&lt;/code&gt; transfers are slightly easier than &lt;code&gt;go-ethereum&lt;/code&gt; transfers, mainly because the provider object sets some necessary fields of the transaction object, such as transaction fee, transaction price, etc., if the original transaction is not sent.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use ethers::prelude::*;
use eyre::Result;
use ethers::signers::{Signer, Wallet};
use ethers::utils::{parse_units, ParseUnits};

const RPC_URL: &amp;amp;str = &quot;http://127.0.0.1:8545&quot;;


#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;()&amp;gt; {
    // 通过私钥创建一个钱包，并用它的公钥作为接受地址
    let prikey = hex::decode(&quot;0xdf57089febbacf7ba0bc227dafbffa9fc08a93fdc68e1e42411a14efcf23656e&quot;).unwrap();
    let wallet = Wallet::from_bytes(&amp;amp;prikey).unwrap();
    println!(&quot;钱包私钥: {:?}&quot;, wallet.signer().to_bytes());
    println!(&quot;钱包公钥: {:?}&quot;, wallet.address());

    // 连接节点
    let provider = Provider::&amp;lt;Http&amp;gt;::try_from(RPC_URL)?;
    let accounts = provider.get_accounts().await?;
    println!(&quot;节点账户: {:?}&quot;, accounts);

    // 设置from,to两个交易字段
    let from = accounts[0];
    let to = wallet.address();

    // 通过单位来构造交易的数值, 而不需要手动打18个0
    let pu: ParseUnits = parse_units(&quot;1.0&quot;, &quot;ether&quot;).unwrap();
    let value = U256::from(pu);
    let tx = TransactionRequest::new().to(to).value(value).from(from);

    // 通过eth_sendTransaction接口发送(或者说广播)交易
    let balance_before = provider.get_balance(from, None).await?;
    let tx = provider.send_transaction(tx, None).await?.await?;
    println!(&quot;{}&quot;, serde_json::to_string(&amp;amp;tx)?);

    // 查看交易前后的余额变化
    // 值得注意的是, 交易需要付出手续费，所以不仅仅是减去 1 ether
    let balance_after = provider.get_balance(from, None).await?;
    assert!(balance_after &amp;lt; balance_before);
    println!(&quot;Balance before {balance_before}&quot;);
    println!(&quot;Balance after {balance_after}&quot;);
    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Token transfer&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ethers-rs&lt;/code&gt; token transfer is much easier than &lt;code&gt;go-ethereum&lt;/code&gt; because of the powerful macro programming support, you can generate code directly at compile time, so you can get code prompts when writing code, which is great for me as a code prompt oriented programmer.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use ethers::{
    contract::abigen,
    middleware::SignerMiddleware,
    providers::{Http, Provider, Middleware},
    signers::{Signer, Wallet},
    types::{Address, U256}
};
use eyre::Result;
use std::{convert::TryFrom, sync::Arc};


const RPC_URL: &amp;amp;str = &quot;http://127.0.0.1:8545&quot;;


#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;()&amp;gt; {
    // 构造本地钱包，用于创建signer对象
    let prikey = hex::decode(&quot;0xdf57089febbacf7ba0bc227dafbffa9fc08a93fdc68e1e42411a14efcf23656e&quot;).unwrap();
    let wallet = Wallet::from_bytes(&amp;amp;prikey).unwrap();
    println!(&quot;钱包公钥: {:?}&quot;, wallet.address());
    let from_address = wallet.address();

    // 创建客户端
    let provider = Provider::&amp;lt;Http&amp;gt;::try_from(RPC_URL)?;
    let to_address: Address = &quot;0xdD2FD4581271e230360230F9337D5c0430Bf44C0&quot;.parse().unwrap();

    // ERC20合约地址
    const ERC20_CONTRACT_ADDRESS: &amp;amp;str = &quot;0xEB1774bc66930a417A76Df89885CeE7c1A29f405&quot;;
    let token_address: Address = ERC20_CONTRACT_ADDRESS.parse()?;
    // 生成合约对象
    abigen!(
        ERC20Contract,
        r#&quot;[
            function balanceOf(address account) external view returns (uint256)
            function decimals() external view returns (uint8)
            function symbol() external view returns (string memory)
            function transfer(address to, uint256 amount) external returns (bool)
            event Transfer(address indexed from, address indexed to, uint256 value)
        ]&quot;#,
    );
    // chain_id在签名验证的时候很重要！！！
    let chain_id = provider.get_chainid().await?.as_u64();
    // contract对象实例化的时候需要一个ARC对象
    let signer =
        Arc::new(SignerMiddleware::new(provider, wallet.with_chain_id(chain_id)));
    let contract = ERC20Contract::new(token_address, signer);

    // 将转账单位设置成 whole_amount * （10^decimals）
    let whole_amount: u64 = 1;
    let decimals = contract.decimals().call().await?;
    let decimal_amount = U256::from(whole_amount) * U256::exp10(decimals as usize);

    // 调用合约transfer接口
    println!(&quot;从账户[{:?}]转账到账户[{:?}]: {:?}&quot;, from_address, to_address, decimal_amount);
    let tx = contract.transfer(to_address, decimal_amount);
    // 等待交易完成
    let pending_tx = tx.send().await?;
    let _mined_tx = pending_tx.await?;

    // 获取余额
    let balance = contract.balance_of(to_address).call().await?;
    println!(&quot;账户[{:?}]当前余额: {:?}&quot;, to_address, balance);
    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Listen for new block&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;use ethers::providers::{Middleware, Provider, StreamExt, Ws};
use eyre::Result;

const WEBSOCKET_RPC_URL: &amp;amp;str = &quot;ws://127.0.0.1:8546&quot;;

#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;()&amp;gt; {
    let provider =
        Provider::&amp;lt;Ws&amp;gt;::connect(WEBSOCKET_RPC_URL)
            .await?;

    // take代表最多获取一个监听数据
    let mut stream = provider.subscribe_blocks().await?.take(1);
    println!(&quot;开始监听，仅监听最多一个区块事件&quot;);
    while let Some(block) = stream.next().await {
        println!(
            &quot;在时间点{:?}, 创建了新的区块号[{}] -&amp;gt; 对应的hash:{:?}&quot;,
            block.timestamp,
            block.number.unwrap(),
            block.hash.unwrap()
        );
    }
    println!(&quot;监听完毕.&quot;);

    // 一直监听
    println!(&quot;开始监听，一直监听，直到程序被关闭&quot;);
    let mut stream = provider.subscribe_blocks().await?;
    while let Some(block) = stream.next().await {
        println!(
            &quot;在时间点: {:?}, 创建了新的区块号[{}] -&amp;gt; 对应的hash:{:?}&quot;,
            block.timestamp,
            block.number.unwrap(),
            block.hash.unwrap()
        );
    }
    println!(&quot;监听完毕.&quot;);
    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Creating/Sending Raw Transactions&lt;/h3&gt;
&lt;p&gt;The purpose of sending raw transactions is to customize the signature. Therefore, there is no need to self-sign just for the sake of self-signing. We can use the &lt;code&gt;SignerMiddleware&lt;/code&gt; object provided by &lt;code&gt;ethers-rs&lt;/code&gt; to wrap the wallet (or private key, or signer) object. Then, we only need to set up the transaction request simply. Unlike directly calling the &lt;code&gt;provider&lt;/code&gt; object, we need to handle the transaction fees and transaction prices ourselves.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use ethers::prelude::*;
use ethers::middleware::{SignerMiddleware};
use eyre::Result;
use ethers::signers::{Signer, Wallet};
use ethers::utils::{parse_units, ParseUnits};

const RPC_URL: &amp;amp;str = &quot;http://127.0.0.1:8545&quot;;


#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;()&amp;gt; {
    // 自定义钱包
    let prikey = hex::decode(&quot;0xdf57089febbacf7ba0bc227dafbffa9fc08a93fdc68e1e42411a14efcf23656e&quot;).unwrap();
    let wallet = Wallet::from_bytes(&amp;amp;prikey).unwrap();
    println!(&quot;钱包私钥: {:?}&quot;, wallet.signer().to_bytes());
    println!(&quot;钱包公钥: {:?}&quot;, wallet.address());

    // 设置收发地址
    let from_address = wallet.address();
    let to_address: Address = &quot;0xdD2FD4581271e230360230F9337D5c0430Bf44C0&quot;.parse().unwrap();

    // 创建交易金额
    let pu: ParseUnits = parse_units(&quot;1.0&quot;, &quot;ether&quot;).unwrap();
    let value = U256::from(pu);

    // 构造交易请求
    let provider = Provider::&amp;lt;Http&amp;gt;::try_from(RPC_URL)?;
    let chain_id = provider.get_chainid().await.unwrap();
    let tx = TransactionRequest::new().to(to_address).value(value).from(from_address).chain_id(chain_id.as_u64());
    // 特别要注意chain_id是否正确!!!
    let wallet =  wallet.with_chain_id(chain_id.as_u64());

    let gas_price = provider.get_gas_price().await?;
    let gas = provider.estimate_gas(&amp;amp;tx.clone().into(), None).await?;
    let tx = tx.gas(gas).gas_price(gas_price);

    // 构造SignerMiddleware, 是provider进一步包装
    let new_provider = SignerMiddleware::new(provider, wallet);
    let nonce1 = new_provider.get_transaction_count(from_address, None).await?;
    let balance_before = new_provider.get_balance(from_address, None).await?;

    let tx = new_provider.send_transaction(tx, None).await.unwrap().await.unwrap();

    let nonce2 = new_provider.get_transaction_count(from_address, None).await?;
    assert!(nonce1 &amp;lt; nonce2);
    println!(&quot;tx: {}&quot;, serde_json::to_string(&amp;amp;tx)?);

    let balance_after = new_provider.get_balance(from_address, None).await?;
    // assert!(balance_after &amp;lt; balance_before);

    println!(&quot;Balance before {balance_before}&quot;);
    println!(&quot;Balance after {balance_after}&quot;);
    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Obtaining the Private Key from a Keystore File&lt;/h3&gt;
&lt;p&gt;The code tests in this article are all performed using Geth&apos;s development mode. Sometimes, you may need to use the private key. In that case, you can use this website to recover the private key:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://lab.miguelmota.com/ethereum-keystore/example/&quot;&gt;https://lab.miguelmota.com/ethereum-keystore/example/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The password for the keystore file in development mode is an empty value, so you don&apos;t need to fill it in.&lt;/p&gt;
&lt;h3&gt;Summary&lt;/h3&gt;
&lt;p&gt;The content in this part is quite simple to implement using ethers-rs because there is no need to compile Solidity source code to generate the corresponding interface code. This is one of the powerful features of ethers-rs and Rust.&lt;/p&gt;
&lt;p&gt;Through these three chapters, we should be able to complete most of the interactions with Ethereum, except for [missing content].&lt;/p&gt;
&lt;h3&gt;Reference Links&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://goethereumbook.org/zh/&quot;&gt;https://goethereumbook.org/zh/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://goethereumbook.org/en/&quot;&gt;https://goethereumbook.org/en/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ethereum.org/en/developers/docs/programming-languages/rust/#rust-projects-and-tools&quot;&gt;https://ethereum.org/en/developers/docs/programming-languages/rust/#rust-projects-and-tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gakonst.com/ethers-rs&quot;&gt;https://gakonst.com/ethers-rs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.ethers.org/v5/&quot;&gt;https://docs.ethers.org/v5/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Derick</author></item><item><title>Go开发者的Rust学习指南:所有权、借用和生命周期</title><link>https://blog.ithuo.net/posts/go-developers-guide-to-rust-ownership-borrowing-and-lifetimes/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-developers-guide-to-rust-ownership-borrowing-and-lifetimes/</guid><pubDate>Sat, 18 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;作为一名Go开发者,你可能对Rust的独特特性感到好奇。Rust以其内存安全和并发安全而闻名,但这些特性也带来了一些新的概念需要学习。本文将介绍Rust中最重要的几个概念:所有权、借用和生命周期,并通过与Go的对比来帮助理解。&lt;/p&gt;
&lt;h2&gt;所有权(Ownership)&lt;/h2&gt;
&lt;p&gt;所有权是Rust最独特的特性之一。在Go中,我们使用垃圾回收来管理内存,而Rust通过所有权系统在编译时就确保了内存安全,无需运行时垃圾回收。&lt;/p&gt;
&lt;p&gt;Rust的所有权规则如下:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;每个值都有一个所有者变量&lt;/li&gt;
&lt;li&gt;同一时间只能有一个所有者&lt;/li&gt;
&lt;li&gt;当所有者离开作用域,值会被自动释放&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;来看一个例子:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fn main() {
    let s1 = String::from(&quot;hello&quot;);
    let s2 = s1;

    println!(&quot;{}&quot;, s1); // 编译错误!
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个例子中,&lt;code&gt;s1&lt;/code&gt;的所有权被转移给了&lt;code&gt;s2&lt;/code&gt;,所以&lt;code&gt;s1&lt;/code&gt;不再有效。这与Go的行为不同,在Go中这段代码是完全合法的。&lt;/p&gt;
&lt;h2&gt;借用(Borrowing)&lt;/h2&gt;
&lt;p&gt;为了让多个部分的代码可以访问数据而不转移所有权,Rust引入了借用的概念。借用通过引用(&lt;code&gt;&amp;amp;&lt;/code&gt;)来实现。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fn main() {
    let s1 = String::from(&quot;hello&quot;);
    let len = calculate_length(&amp;amp;s1);
    println!(&quot;The length of &apos;{}&apos; is {}.&quot;, s1, len);
}

fn calculate_length(s: &amp;amp;String) -&amp;gt; usize {
    s.len()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里&lt;code&gt;calculate_length&lt;/code&gt;函数借用了&lt;code&gt;s1&lt;/code&gt;的引用,而不是获取所有权。这允许&lt;code&gt;main&lt;/code&gt;函数在调用后仍然可以使用&lt;code&gt;s1&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;Rust还有可变借用(&lt;code&gt;&amp;amp;mut&lt;/code&gt;)的概念,允许修改借用的值:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fn main() {
    let mut s = String::from(&quot;hello&quot;);
    change(&amp;amp;mut s);
}

fn change(some_string: &amp;amp;mut String) {
    some_string.push_str(&quot;, world&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;生命周期(Lifetimes)&lt;/h2&gt;
&lt;p&gt;生命周期是Rust中另一个重要概念,它帮助编译器确保所有的借用都是有效的。大多数情况下,生命周期是隐式的,但有时需要显式标注:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fn longest&amp;lt;&apos;a&amp;gt;(x: &amp;amp;&apos;a str, y: &amp;amp;&apos;a str) -&amp;gt; &amp;amp;&apos;a str {
    if x.len() &amp;gt; y.len() { x } else { y }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里的&lt;code&gt;&apos;a&lt;/code&gt;是一个生命周期参数,它表示返回的引用的生命周期与参数&lt;code&gt;x&lt;/code&gt;和&lt;code&gt;y&lt;/code&gt;的生命周期一样长。&lt;/p&gt;
&lt;h2&gt;与Go的对比&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;内存管理:Go使用垃圾回收,Rust使用所有权系统。&lt;/li&gt;
&lt;li&gt;并发安全:Go通过通道和&lt;code&gt;sync&lt;/code&gt;包实现,Rust通过所有权和类型系统在编译时保证。&lt;/li&gt;
&lt;li&gt;错误处理:Go使用多返回值,Rust使用&lt;code&gt;Result&lt;/code&gt;类型。&lt;/li&gt;
&lt;li&gt;泛型:Rust的泛型更加强大和灵活。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;结论&lt;/h2&gt;
&lt;p&gt;对于Go开发者来说,Rust的所有权、借用和生命周期概念可能初看起来很复杂。但这些概念使得Rust能够在编译时保证内存和线程安全,同时又保持高性能。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>.NET Aspire简介：使用.NET 8简化云原生开发</title><link>https://blog.ithuo.net/posts/introduction-to-net-aspire-simplify-cloud-native-development-with-net-8/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/introduction-to-net-aspire-simplify-cloud-native-development-with-net-8/</guid><pubDate>Wed, 15 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;为了帮助简化云应用程序的复杂性，微软推出了.NET Aspire&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/df9cd321d6d8708c21ed0e472d413a0f.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;.NET Aspire 是一个用于构建弹性、可观察和可配置的云原生应用程序的成熟套件。它包括一组经过精心挑选的组件，通过默认包含服务发现、遥测、弹性和健康检查来增强云原生能力。结合了复杂场景但提升简单的本地开发人员体验，.NET Aspire 使您能够轻松发现、获取和配置云原生应用程序的基本依赖项。&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;.NET Aspire之旅&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;首先，让我们先浏览一下新的 &lt;code&gt;.NET Aspire Starter&lt;/code&gt; 模板，并在文章后面深入讨论之前触及所有功能。本节是一个会话概述，您可以沿着阅读。您需要最新的.NET 8和Visual Studio 2022预览版（17.9预览版1）。如果您使用的是Linux或Mac，您仍然可以沿着学习所有内容，但所给出的一些工具示例还不可用。&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;Visual Studio解决方案教程&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;初学者应用程序旨在让您启动并运行一个可以试用的.NET Aspire解决方案。该应用程序由两个项目和一个Redis缓存组成。前端项目是一个Blazor Web应用程序，它调用后端API获取天气信息。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/42b19f45c15135189141a9749a83627f.png&quot; alt=&quot;dotnetAspire-Solution-Explorer2.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;你会注意到两个你以前没有见过的新项目 &lt;code&gt;&amp;lt;appname&amp;gt;.AppHost&lt;/code&gt; 和 &lt;code&gt;&amp;lt;appname&amp;gt;.ServiceDefaults&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;AppHost&lt;/code&gt; 项目将运行获取分布式应用程序所需的任何.NET项目、容器或可执行文件。在Visual Studio中，调试将附加到所有正在运行的项目，允许您单步执行应用程序中的每个服务。我们将在后面的文章中深入研究这个项目以及其中的代码是什么样的。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ServiceDefaults&lt;/code&gt; 项目包含应用于应用程序中每个项目的公共服务中心逻辑。这是配置服务发现、遥测和健康检查端点等横切关注点的地方。我们希望这在所有项目中保持一致，但也理解团队和组织可能希望调整一些设置。项目中的共享代码是我们能找到的实现这些目标的最容易理解和开发人员友好的机制。&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;仪表板-您的应用监控和检查中心&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;在Visual Studio或dotnet中通过命令行运行 F5 启动.NET Aspire启动器应用程序，将您带到开发人员仪表板。这个仪表板是调试分布式应用程序的重要工具，它提供了服务的统一视图以及日志、指标和跟踪。&lt;/p&gt;
&lt;p&gt;这个仪表板不仅仅是一个进入云原生应用程序的窗口;它是一个交互式平台，可以为您的项目提供有价值的见解，并突出显示任何错误，从而进行更深入的调查。下面是一个图像，显示了一个已识别错误的项目，用红点表示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/a52ef75c46e04dbfc66573ea8b27c3ae.png&quot; alt=&quot;dotnet-Aspire-dashboard-projects-errors.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;我们还可以看到所有项目的日志，甚至还有一个分布式跟踪，显示了对天气页面的请求。跟踪是诊断分布式系统中问题的不可或缺的工具。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/d2f51a733b3c73064065366046173948.png&quot; alt=&quot;dotnet-Aspire-trace-view-filter.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;开发人员仪表板是您收集所有开发时间诊断数据以及对开发机器上的速度减慢和错误进行故障排除的地方。它使用的开放标准与您在配置生产遥测系统（如Grafana+Prometheus、Application Insights等）时在生产中使用的开放标准完全相同。&lt;/p&gt;
&lt;p&gt;几年前，我们进行了一个名为&lt;code&gt;Project Tye&lt;/code&gt;的实验，从那个实验中学到的许多东西现在都可以在.NET Aspire中使用，包括我们在那个实验中首次尝试的这个仪表板。如果你喜欢&lt;code&gt;Project Tye&lt;/code&gt;并希望它继续下去，那么我们认为你会喜欢.NET Aspire。&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;Components 组件&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;现在让我们开始看看这些项目有什么不同。首先，Web项目有一个NuGet包，其名称为 &lt;code&gt;Aspire.StackExchange.Redis.OutputCaching&lt;/code&gt; ，其中包含 &lt;code&gt;Aspire&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/efe421747645cfce08e2099be0bd8753.png&quot; alt=&quot;dotnetAspire-Components-Dependencies-Packages.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;如果你沿着看，没有看到这个包，你可能在创建项目的时候没有选中“&lt;strong&gt;使用Redis缓存&lt;/strong&gt;”。&lt;/p&gt;
&lt;p&gt;这个NuGet包就是我们所说的 &lt;code&gt;.NET Aspire Component&lt;/code&gt; 。组件是将SDK配置为在云环境中运行的粘合库。每个组件必须：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提供JSON Schema以进行配置，从而在 &lt;code&gt;appsettings.json&lt;/code&gt; 中提供语句完成。&lt;/li&gt;
&lt;li&gt;利用可配置的恢复模式（如重试、超时和断路器）最大限度地提高可用性。&lt;/li&gt;
&lt;li&gt;公开运行状况检查，使应用程序能够跟踪和响应远程服务的运行状况。&lt;/li&gt;
&lt;li&gt;使用现代的.NET抽象（ &lt;code&gt;ILogger&lt;/code&gt; ， &lt;code&gt;Meter&lt;/code&gt; ， &lt;code&gt;Activity&lt;/code&gt; ）提供集成的日志记录、指标和跟踪。&lt;/li&gt;
&lt;li&gt;提供扩展方法，将服务从SDK“粘合”到DI容器，并为注册的类型提供正确的生存期。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们将在后面的文章中详细介绍组件。关键的要点是.NET Aspire Components配置依赖项以荣誉一组我们认为可以帮助消费者在云中取得成功的需求。它们不会包装/隐藏实际的SDK/库，而是充当粘合剂，以确保库配置了一组默认值，并正确地注册到DI。&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;代码&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;现在让我们看看Blazor应用程序中调用天气API的代码，然后看看我们前面讨论过的AppHost中的一些代码。首先，在我们的web项目的Program.cs中，你可以看到这样的代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;builder.Services.AddHttpClient&amp;lt;WeatherApiClient&amp;gt;(
    client =&amp;gt; client.BaseAddress = new(&quot;http://apiservice&quot;));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是配置我们的Web前端，以便能够调用天气API。但有几件事是不寻常的，即这个 &lt;code&gt;apiservice&lt;/code&gt; 名字来自哪里？为了回答这个问题，我们将第一次查看 &lt;code&gt;AppHost&lt;/code&gt; 项目，这里是该项目的&lt;code&gt;Program.cs&lt;/code&gt;文件。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var builder = DistributedApplication.CreateBuilder(args);

var cache = builder.AddRedisContainer(&quot;cache&quot;);

var apiservice = builder.AddProject&amp;lt;Projects.AspireApp_ApiService&amp;gt;(&quot;apiservice&quot;);

builder.AddProject&amp;lt;Projects.AspireApp_Web&amp;gt;(&quot;webfrontend&quot;)
    .WithReference(cache)
    .WithReference(apiservice);

builder.Build().Run();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行此代码是因为 &lt;code&gt;AppHost&lt;/code&gt; 是您的启动项目。它运行您的项目及其依赖项，并适当地配置它们，使它们能够进行通信。我们的目标之一是尽可能地从开发人员流程中删除端口和连接字符串。我们通过服务发现机制来实现这一点，该机制允许开发人员在进行HTTP调用时使用逻辑名称而不是IP地址和端口。您可以在这里看到，我将我的API命名为 &lt;code&gt;apiservice&lt;/code&gt; ，然后将其作为引用传递给前端，然后可以在通过 &lt;code&gt;IHttpClientFactory&lt;/code&gt; 进行HTTP调用时使用 &lt;code&gt;apiservice&lt;/code&gt; 作为名称。由于与&lt;code&gt;Polly&lt;/code&gt;项目的集成，使用此方法进行的调用还将自动重试并处理瞬时故障。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;AppHost&lt;/code&gt;设置您的应用程序依赖项和要求，而.NET Aspire工具在您的开发迭代中满足这些要求。&lt;/p&gt;
&lt;h3&gt;深入介绍&lt;/h3&gt;
&lt;h4&gt;组件&lt;/h4&gt;
&lt;p&gt;我们将从组件开始深入研究。.NET Aspire组件旨在解决我们从客户开始云原生开发时听到的痛苦，有很多技术/配置必须正确，并且不清楚从哪条路开始。我们通过对组件需要提供的内容发表意见来帮助实现这一点，要求所有组件至少提供弹性默认值，健康检查，设置遥测，并与DI集成。为了强调这一点，让我们来看看一个准备生产的应用程序可能会在他们的应用程序中配置Redis：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用Redis客户端库添加Redis包。&lt;/li&gt;
&lt;li&gt;发现并添加健康检查库，以便您的应用可以响应Redis是否可用。这一点经常被忽略，但在实践中很有用。&lt;/li&gt;
&lt;li&gt;将Redis添加到DI并配置连接字符串。这很棘手，因为你需要知道Redis客户端库类型应该有什么生命周期。这需要研究。&lt;/li&gt;
&lt;li&gt;配置Redis客户端库以将日志输出发送到遥测系统。&lt;/li&gt;
&lt;li&gt;日志和指标不同，需要不同的管道。&lt;/li&gt;
&lt;li&gt;决定需要什么样的弹性策略和逻辑，并配置Redis或使用可以实现弹性策略的Poly等库包装调用。这再次需要研究Redis的能力以及你应该拥有什么样的弹性策略，这通常是你一开始就不知道的，导致人们在没有它的情况下进行运输，直到生产中出现一些中断，而这些中断本可以通过具有指数回退的重试策略来避免。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果我们将其与使用.NET Aspire进行对比：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;添加.NET Aspire Redis包。&lt;/li&gt;
&lt;li&gt;在构建器上调用 &lt;code&gt;AddRedis&lt;/code&gt; 。&lt;/li&gt;
&lt;li&gt;可选地覆盖appSettings.json中的默认配置（它现在是模块化的，因此您可以完成发现可以设置的内容）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;.NET Aspire组件经过精心设计，可为您提供最佳的生产就绪配置，而不会隐藏底层SDK。在上面提到的两个例子中，使用Redis的代码将始终使用相同的Redis客户端库和类型。&lt;/p&gt;
&lt;p&gt;组件必须满足以下要求才能被视为可供用途：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提供详细的、系统化的配置。&lt;/li&gt;
&lt;li&gt;设置运行状况检查以跟踪和响应远程服务运行状况。&lt;/li&gt;
&lt;li&gt;提供默认的、可配置的弹性模式（重试、超时等）以最大限度地提高可用性。&lt;/li&gt;
&lt;li&gt;提供集成的日志记录、度量和跟踪，使组件可观察。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面列出了我们的初始组件集，更多文档可以在.NET Aspire组件概述中找到|Microsoft Learn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;与云无关的组件&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Component&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://learn.microsoft.com/dotnet/aspire/database/postgresql-entity-framework-component&quot;&gt;PostgreSQL Entity Framework Core&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Provides a client library for accessing PostgreSQL databases using Entity Framework Core.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://learn.microsoft.com/dotnet/aspire/database/postgresql-component&quot;&gt;PostgreSQL&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Provides a client library for accessing PostgreSQL databases.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://learn.microsoft.com/dotnet/aspire/messaging/rabbitmq-client-component&quot;&gt;RabbitMQ&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Provides a client library for accessing RabbitMQ.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://learn.microsoft.com/dotnet/aspire/caching/stackexchange-redis-distributed-caching-component&quot;&gt;Redis Distributed Caching&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Provides a client library for accessing Redis caches for distributed caching.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://learn.microsoft.com/dotnet/aspire/caching/stackexchange-redis-output-caching-component&quot;&gt;Redis Output Caching&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Provides a client library for accessing Redis caches for output caching.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://learn.microsoft.com/dotnet/aspire/caching/stackexchange-redis-component&quot;&gt;Redis&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Provides a client library for accessing Redis caches.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://learn.microsoft.com/dotnet/aspire/database/sql-server-entity-framework-component&quot;&gt;SQL Server Entity Framework Core&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Provides a client library for accessing SQL Server databases using Entity Framework Core.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://learn.microsoft.com/dotnet/aspire/database/sql-server-component&quot;&gt;SQL Server&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Provides a client library for accessing SQL Server databases.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Azure特定组件&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Component&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://learn.microsoft.com/dotnet/aspire/storage/azure-storage-blobs-component&quot;&gt;Azure Blob Storage&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Provides a client library for accessing Azure Blob Storage.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://learn.microsoft.com/dotnet/aspire/database/azure-cosmos-db-entity-framework-component&quot;&gt;Azure Cosmos DB Entity Framework Core&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Provides a client library for accessing Azure Cosmos DB databases with Entity Framework Core.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://learn.microsoft.com/dotnet/aspire/database/azure-cosmos-db-component&quot;&gt;Azure Cosmos DB&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Provides a client library for accessing Azure Cosmos DB databases.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://learn.microsoft.com/dotnet/aspire/security/azure-security-key-vault-component&quot;&gt;Azure Key Vault&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Provides a client library for accessing Azure Key Vault.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://learn.microsoft.com/dotnet/aspire/messaging/azure-service-bus-component&quot;&gt;Azure Service Bus&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Provides a client library for accessing Azure Service Bus.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://learn.microsoft.com/dotnet/aspire/storage/azure-storage-queues-component&quot;&gt;Azure Storage Queues&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Provides a client library for accessing Azure Storage Queues.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;&lt;strong&gt;Application Model 应用模型&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;.NET Aspire应用程序中的 &lt;code&gt;AppHost&lt;/code&gt; 项目让您可以用自己喜欢的.NET语言（最初支持C#）表达应用程序的需求。它负责协调应用程序在开发机器上的运行。&lt;/p&gt;
&lt;p&gt;编排是.NET Aspire的核心功能，旨在简化云原生应用程序不同部分之间的连接和配置。.NET Aspire提供了有用的抽象，允许您编排服务发现，环境变量和容器配置等问题，而无需管理低级别的实现细节。这些抽象还提供了跨具有许多组件和服务的应用程序的一致设置模式。&lt;/p&gt;
&lt;p&gt;.NET Aspire编排有助于解决以下问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;应用组合：定义组成应用的资源，包括.NET项目、容器、可执行文件或云资源。&lt;/li&gt;
&lt;li&gt;服务发现：确定不同的资源如何相互通信。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;例如，使用.NET Aspire，以下代码创建了一个本地Redis容器资源，一个API的项目资源，并在“&lt;strong&gt;webfrontend&lt;/strong&gt;”项目中配置了适当的连接字符串和URL。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var builder = DistributedApplication.CreateBuilder(args);

var cache = builder.AddRedisContainer(&quot;cache&quot;);

var apiservice = builder.AddProject&amp;lt;Projects.AspireApp_ApiService&amp;gt;(&quot;apiservice&quot;);

builder.AddProject&amp;lt;Projects.AspireApp_Web&amp;gt;(&quot;webfrontend&quot;)
    .WithReference(cache)
    .WithReference(apiservice);

builder.Build().Run();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;“&lt;strong&gt;webfrontend&lt;/strong&gt;”项目现在可以向 &lt;code&gt;http://apiservice&lt;/code&gt; 发出HTTP请求，而无需担心端口映射。Redis连接字符串更加透明，因为.NET Aspire组件配置Redis客户端使用自动提供的连接字符串。这消除了开发流程中容易出错的设置的大量来源，并简化了入门和入门。如果您在生产中使用服务发现，即使只有默认的&lt;strong&gt;Kubernetes&lt;/strong&gt;功能，那么这也将比手动配置更接近生产配置。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;内置资源&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;项目：.NET项目，例如ASP.NET Core Web应用程序。&lt;/li&gt;
&lt;li&gt;容器：容器镜像，例如Docker镜像。&lt;/li&gt;
&lt;li&gt;可执行文件：可执行文件。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;与云无关的扩展&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当您为相应的资源添加NuGet包（组件）时，这些组件中的每一个都可用。对于其中的每一个，你可以让.NET Aspire在开发过程中启动一个容器，或者通过连接字符串连接到现有的/外部的资源。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Postgress&lt;/li&gt;
&lt;li&gt;RabbitMQ&lt;/li&gt;
&lt;li&gt;Redis&lt;/li&gt;
&lt;li&gt;SQL Server&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Azure特定扩展&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当您为相应的资源添加NuGet包（组件）时，这些方法中的每一个都可用。Azure存储是目前唯一支持运行本地容器的资源，其余资源需要实际Azure资源的连接信息。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Azure Storage (blobs, Tables, Queues)&lt;/li&gt;
&lt;li&gt;Azure Cosmos DB&lt;/li&gt;
&lt;li&gt;Azure KeyVault&lt;/li&gt;
&lt;li&gt;Azure Redis Cache&lt;/li&gt;
&lt;li&gt;Azure Service Bus&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Developer Dashboard&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;.NET Aspire仪表板仅在AppHost运行时可见，并将在您启动项目时自动启动。左侧导航提供了指向我们将在此处描述的仪表板不同部分的链接。此外，仪表板右上角的齿轮图标提供了对设置页面的访问，该页面允许您配置仪表板体验。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/11ed413f2b6637be84daacc9085068b7.png&quot; alt=&quot;dotnet-Aspire-metrics-view.png&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;项目：项目页面是仪表板的主页，它列出了应用程序中的所有项目资源。它的主要功能是向你显示每个项目的状态，并给予你应用程序各部分的URL。当一个项目记录了错误时，它还会显示一个标记，让你轻松地锁定问题。&lt;/li&gt;
&lt;li&gt;容器：此页面与项目页面相同，但用于应用程序的容器资源。在我们上面的教程中，Redis缓存容器将显示在这里。&lt;/li&gt;
&lt;li&gt;可执行文件：此页与项目页相同，但用于应用程序的可执行文件资源。&lt;/li&gt;
&lt;li&gt;日志：dashbaord的日志部分提供了在中央位置访问应用程序所有部分的日志。
&lt;ul&gt;
&lt;li&gt;项目编号：您可以在这里查看.NET项目中日志提供程序的输出，您可以在每个项目之间切换，每个日志严重性都用不同的颜色表示。&lt;/li&gt;
&lt;li&gt;容器目录：此页面与项目目录相同，但用于容器。&lt;/li&gt;
&lt;li&gt;可执行文件目录：此页面与项目目录相同，但用于可执行文件。&lt;/li&gt;
&lt;li&gt;结构化日志：结构化日志页面提供了所有日志的可过滤视图。结构化日志维护日志消息的属性，以便它们可以单独过滤/搜索，而其他日志页面的所有属性都合并到一个字符串日志消息中。&lt;/li&gt;
&lt;li&gt;跟踪：跟踪页显示了通过应用程序所有部分的单个操作的路径，这是一个分布式跟踪。这个视图在发现瓶颈、减速和诊断只有在使用整个系统而不是孤立地使用时才会出现的其他行为方面非常有价值。我们在上面的教程部分展示了一个跟踪视图的截图，突出显示了如何在一个视图中看到使用Redis缓存，API和前端的单个操作。&lt;/li&gt;
&lt;li&gt;指标：“指标”页面显示应用程序的所有指标。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可&lt;strong&gt;观测性&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;.NET Aspire应用程序默认情况下是可观察的。出色的可观察性意味着您可以通过从运行中的应用程序收集的所有数据（特别是日志、指标和跟踪）确定解决方案中发生了什么，尤其是在停机期间。如果您无法确定正在发生的事情，那么仅仅拥有日志和指标并不能使整个系统变得可观察，您需要在正确的时间在正确的视图中显示正确的数据。&lt;/p&gt;
&lt;p&gt;这意味着，对于一个应用程序是可观察的，那么：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;分布式应用程序的所有部分都需要以您可以使用的方式提供数据，包括.NET本身、您使用的库以及您自己的应用程序代码。&lt;/li&gt;
&lt;li&gt;这些数据需要发送到您可以访问的地方。&lt;/li&gt;
&lt;li&gt;查看/查询/理解数据的工具需要存在。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在.NET中，我们一直在越来越多地投入支持&lt;strong&gt;Open Telemetry&lt;/strong&gt;作为数据的格式，采用&lt;strong&gt;Open Telemetry&lt;/strong&gt;命名和数据结构，以及&lt;code&gt;Open Telemetry Protocol&lt;/code&gt;（OTLP）将数据从应用程序中提取出来并进入工具生态系统。&lt;/p&gt;
&lt;p&gt;在.NET Aspire中，我们在 &lt;code&gt;ServiceDefaults&lt;/code&gt; 项目中提供了默认连接Open Telemetry的代码。我们使用共享代码是因为有一些约定，比如健康端点的名称，我们预计有些人会想要为他们的项目或公司定制这些约定。在实验中，我们发现共享代码在定义这些类型的默认值方面提供了更好的体验，人们可以调整这些类型，而不是将它们放在具有配置设置的库中。&lt;/p&gt;
&lt;p&gt;.NET Aspire还提供了我们上面提到的开发人员仪表板，它为您提供了应用程序的所有日志，指标和跟踪。仪表板的一个突出功能是Traces视图，它提供了通过应用程序的请求的分布式跟踪。在下面的示例中，我们向 &lt;code&gt;Aspire Starter App&lt;/code&gt; 模板的天气页面发出了请求。您可以看到请求如何从前端转到Redis缓存，以查看数据是否被缓存（DATA redis GET行），然后因为该高速缓存中没有数据，它会调用后端API，最后缓存该数据。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/ce88cf6c5093c0f9684e0023e74a7d15.png&quot; alt=&quot;dotnetAspire-Redis-Cache-View.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这种类型的视图使得查找诸如用户操作之类的东西，这些操作会导致系统中的低效路径。您将能够立即看到正在进行的多个数据库调用或正在减慢系统其他部分的单个服务。如果没有这种类型的数据和数据视图，这些类型的问题可能很难发现。&lt;/p&gt;
&lt;h3&gt;服务发现&lt;/h3&gt;
&lt;p&gt;构建任何分布式应用程序的关键之一是调用远程服务的能力。作为.NET Aspire的一部分，我们构建了一个新的服务发现库&lt;code&gt;Microsoft.Extensions.ServiceDiscovery&lt;/code&gt;。该库提供了客户端服务发现和负载平衡的核心抽象和各种实现，可以与&lt;code&gt;HttpClientFactory&lt;/code&gt;和&lt;code&gt;YARP&lt;/code&gt;无缝集成，也可以在部署的环境&lt;strong&gt;Kuberentes&lt;/strong&gt;和&lt;strong&gt;Azure&lt;/strong&gt;容器应用程序中集成。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;部署.NET Aspire应用程序&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;.NET Aspire应用程序的最终构件是可以部署到云环境的.NET应用程序和配置。依靠.NET Aspire强大的容器优先思想，.NET SDK本机容器构建可作为一个有价值的工具，轻松将这些应用程序发布到容器中。&lt;/p&gt;
&lt;p&gt;虽然.NET Aspire本身并不提供直接的机制来将应用程序部署到其最终目标机器，但上面描述的应用程序模型知道应用程序的所有信息，它的依赖关系，配置以及与每个服务的连接。应用程序模型可以生成一个清单定义，该定义描述工具可以使用、扩充和构建以进行部署的所有这些关系和依赖项。&lt;/p&gt;
&lt;p&gt;通过此清单，我们可以使用Azure容器应用程序以最简单、最快的方式将您的.NET Aspire应用程序导入&lt;strong&gt;Azure&lt;/strong&gt;。使用&lt;code&gt;Azure Developer CLI&lt;/code&gt;和.NET Aspire中的新功能，这些组合体验使您能够快速检测.NET Aspire环境，了解应用程序，并立即在一个步骤中配置和部署Azure资源。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;现有应用&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;到目前为止，我们已经在这篇博客文章中展示了很多新的应用程序，但是.NET Aspire也可以与现有的应用程序一起使用，因为它可以逐步采用堆栈的各个部分。&lt;/p&gt;
&lt;p&gt;.NET Aspire是.NET 8的一部分。因此，您需要在尝试使用堆栈的任何部分之前进行升级。我们在这里提供了工具和指导来帮助您：升级助手|.NET（microsoft.com）。如果你想使用Visual Studio工具，你还需要最新的Visual Studio预览版，在撰写本文时是17.9。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/328ea874b0f522c340c4323eabe9c6c8.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;然后，系统将提示您确认项目和操作。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/ab6584fb647e24b2ca1f87dff527dcb9.png&quot; alt=&quot;dotnetAspire-Add-Orchestrator-Support.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这将创建一个 &lt;code&gt;AppHost&lt;/code&gt; 和 &lt;code&gt;ServiceDefaults&lt;/code&gt; 项目，您选择的项目将已添加到 &lt;code&gt;AppHost&lt;/code&gt; 。您现在可以启动AppHost项目，并将看到开发人员仪表板。从这里，您可以添加对 &lt;code&gt;ServiceDefaults&lt;/code&gt; 项目的引用，并在应用程序构建器上调用 &lt;code&gt;AddServiceDefaults()&lt;/code&gt; 方法。这将为此项目设置Open Telemetry、运行状况检查端点、服务发现和默认弹性模式。&lt;/p&gt;
&lt;p&gt;当不使用Visual Studio时，您仍然可以使用 &lt;code&gt;dotnet new&lt;/code&gt; 将 &lt;code&gt;AppHost&lt;/code&gt; 和 &lt;code&gt;ServiceDefaults&lt;/code&gt; 项目添加到现有解决方案中，但它们不会像上面的示例那样引用现有项目。&lt;/p&gt;
&lt;p&gt;如果您正在使用任何具有组件的服务，您现在可以切换到.NET Aspire组件。这可能意味着你可以删除一些显式的配置，如果你已经设置了组件自己做的事情。您还可以在任何.NET 8应用程序中自由使用组件，而无需编排。这将使您获得应用于组件的弹性和其他配置，但您不会获得.NET Aspire的其余部分，如仪表板，服务发现和自动端口，URL或连接字符串。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;结论&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们非常高兴今天能向您提供.NET Aspire的第一个预览版。基于.NET 8中坚如磐石的基础知识和令人难以置信的高效API表面，我们相信您会喜欢使用.NET Aspire构建云原生应用程序的生产力。&lt;/p&gt;
&lt;p&gt;Get started today with these resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/dotnet/aspire/setup-tooling?tabs=visual-studio#install-net-aspire&quot;&gt;Download the Aspire workload using the Visual Studio Installer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/dotnet/aspire/get-started/quickstart-build-your-first-aspire-app&quot;&gt;Build your first .NET Aspire solution&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We also have some samples showcasing a few things we think are interesting:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Node frontend with .NET Backend: &lt;a href=&quot;https://github.com/dotnet/aspire-samples/tree/main/samples/AspireWithNode&quot;&gt;https://github.com/dotnet/aspire-samples/tree/main/samples/AspireWithNode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;DAPR integration: &lt;a href=&quot;https://github.com/dotnet/aspire-samples/tree/main/samples/AspireWithDapr&quot;&gt;https://github.com/dotnet/aspire-samples/tree/main/samples/AspireWithDapr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The eShop sample application all running with Aspire: &lt;a href=&quot;https://github.com/dotnet/eshop&quot;&gt;https://github.com/dotnet/eshop&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;有反馈可以联系 &lt;a href=&quot;https://github.com/dotnet/aspire&quot;&gt;https://github.com/dotnet/aspire&lt;/a&gt;.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>.NET 8发布会</title><link>https://blog.ithuo.net/posts/net-8-release-conference/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/net-8-release-conference/</guid><pubDate>Tue, 14 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Microsoft在今天发布了 &lt;strong&gt;.NET 8.0 LTS&lt;/strong&gt;版本，这个版本更新了以下内容&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;性能提升&lt;/li&gt;
&lt;li&gt;云原生支持，发布了.NET Aspire提供服务注册发现，可观测性，云原生部署支持等特性&lt;/li&gt;
&lt;li&gt;对于AI研发的支持，可以很方便的接入OpenAI的API，加快dotnet语言架构下AI产品的问世&lt;/li&gt;
&lt;li&gt;Blazor升级：使用单个强大的组件模型来处理Blazor的所有Web UI需求&lt;/li&gt;
&lt;li&gt;MAUI更新：使用.NET MAUI将您的移动的应用程序部署到最新版本的iOS和Android&lt;/li&gt;
&lt;li&gt;C#12语言特性更新&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/661abd14ff3e544152a31e0a645739b2.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;迄今为止最快的.NET&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;.NET 8在整个堆栈中带来了数千项性能改进。一个名为动态配置文件引导优化（PGO）的新代码生成器可以根据实际使用情况优化您的代码，默认情况下可以将应用的性能提高20%。现在支持的AVX-512指令集使您能够对512位数据向量执行并行操作，这意味着您可以在更短的时间内处理更多的数据。原始类型（数值及以上）现在实现了一个新的可格式化和可解析接口，使它们能够直接格式化和解析为UTF-8，而无需任何代码转换开销。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/ff54dba447c35d9f6eefbd266b920daf.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;.NET Aspire -一个自定义的堆栈，用于构建可观察的，生产就绪的云原生应用程序微服务框架组件&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;.NET Aspire是一个堆栈，用于使用. NET构建弹性，可观察和可配置的云原生应用程序。它包括一组针对云原生增强的策划组件，默认情况下包括遥测，弹性，配置和健康检查。为复杂的服务提供简单的本地开发人员体验，.NET Aspire可以在轻松发现、获取和配置云原生应用程序的基本依赖项。今天发布了.NET Aspire的第一个预览版。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/f8e683a4a51c0deec5a273242b00673b.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;.NET 8容器增强功能-更安全，更紧凑，更高效&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;使用容器打包您的应用程序比以往任何时候都更容易，更安全。每个.NET映像都包含一个非root用户，从而通过一行配置实现更安全的容器。.NET SDK工具发布的容器镜像没有Dockerfile，默认情况下是非root。由于更小的.NET基础映像-包括我们映像的新实验变体，可为原生AOT提供真正最小的应用程序大小，因此可以更快地部署容器化应用程序。选择使用新的Chiseled Ubuntu映像变体进行更多的安全加固，以进一步减少您的攻击面。使用Dockerfiles或SDK工具，为任何架构构建应用和容器镜像。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/d034369a960a26ac6fd7f0abc8dfbc95.png&quot; alt=&quot;Containers2.png&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;原生AoT -迈向更高密度可持续计算之旅&lt;/h2&gt;
&lt;p&gt;将.NET应用程序编译为使用更少内存并立即启动的本机代码。无需等待JIT（即时）编译器在运行时编译代码。无需部署JIT编译器和IL代码。AOT应用仅部署应用所需的代码。您的应用现在可以在不允许JIT编译器的受限环境中运行。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/cac41bf4275abd80ecdcf22efd041f51.png&quot; alt=&quot;AOTOptimizations4.png&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;人工智能-将AI融入.NET应用程序&lt;/h2&gt;
&lt;p&gt;生成式人工智能和大型语言模型正在改变人工智能领域，为开发人员提供在应用程序中创建独特的人工智能体验的能力。.NET 8通过.NET SDK中一流的开箱即用AI功能以及与多个工具的无缝集成，使您可以轻松利用AI。&lt;/p&gt;
&lt;p&gt;各种示例和参考模板，展示模式和实践，现在可以让开发人员轻松入门：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dotnet/eShop&quot;&gt;Customer Chatbot&lt;/a&gt;&lt;a href=&quot;https://github.com/dotnet/eShop&quot;&gt; &lt;/a&gt;&lt;a href=&quot;https://github.com/dotnet/eShop&quot;&gt; 客户聊天机器人&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Azure-Samples/azure-search-openai-demo-csharp&quot;&gt;Retrieval Augmented Generation&lt;/a&gt;&lt;a href=&quot;https://github.com/Azure-Samples/azure-search-openai-demo-csharp&quot;&gt;检索增强生成&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://devblogs.microsoft.com/dotnet/demystifying-retrieval-augmented-generation-with-dotnet/&quot;&gt;Developing Apps using Azure AI services&lt;/a&gt;&lt;a href=&quot;https://devblogs.microsoft.com/dotnet/demystifying-retrieval-augmented-generation-with-dotnet/&quot;&gt;使用Azure AI服务开发应用&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/83deff5b4288b662a8a1d03f7cee1eff.png&quot; alt=&quot;InfuseAIdotnetapps1.png&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Blazor -使用.NET构建全栈Web应用程序&lt;/h2&gt;
&lt;p&gt;.NET 8中的Blazor可以同时使用服务器和客户端来处理所有的Web UI需求。这是全栈Web UI！通过几项新的增强功能，专注于优化页面加载时间，可扩展性和提升用户体验，开发人员现在可以在同一个应用程序中使用Blazor Server和Blazor WebAssembly，在运行时自动将用户从服务器转移到客户端。由于新的基于“Jiterpreter”的运行时和新的内置组件，您的.NET代码在WebAssembly上运行得更快。作为增强.NET 8中整体身份验证、授权和身份管理的一部分，Blazor现在支持生成完整的基于Blazor的Identity UI。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/3f7d7974ae4067da8edd66710f7becdb.png&quot; alt=&quot;Blazor2.png&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;.NET MAUI -提升性能、可靠性和开发人员体验&lt;/h2&gt;
&lt;p&gt;..NET MAUI为您提供了一个单一的项目系统和单一的代码库来构建WinUI，Mac Catalyst，iOS和Android应用程序。原生AOT（实验性）现在支持针对类iOS平台。针对.NET MAUI的新Visual Studio代码扩展为您提供了开发跨平台.NET移动的和桌面应用程序所需的工具。现在支持Xcode 15和Android API 34，允许您针对最新版本的iOS和Android。在性能、控件和UI元素以及特定于平台的行为方面进行了大量的质量改进，例如桌面交互添加了更好的点击处理、键盘侦听器等。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/6a436844619283a769b1daa8101f794d.png&quot; alt=&quot;dotnetMAUIin8-1.png&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;C# 12特性-简化语法，提高开发人员的生产力&lt;/h2&gt;
&lt;p&gt;C# 12让你的编程体验更高效、更愉快。现在，您可以使用简单而优雅的语法在任何类和结构中创建主构造函数。没有更多的样板代码来初始化您的字段和属性。使用简洁而富有表现力的语法创建数组、span和其他集合类型时，您会感到非常高兴。在lambda表达式中为参数使用新的默认值。没有更多的重载或空检查来处理可选参数。你甚至可以使用 &lt;code&gt;using&lt;/code&gt; alias指令来给任何类型别名，而不仅仅是命名类型！&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Collection expressions&lt;/strong&gt; &lt;strong&gt;集合表达式&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Create a list:
List&amp;lt;int&amp;gt; a = [1, 2, 3, 4, 5, 6, 7, 8];

// Create a span
Span&amp;lt;char&amp;gt; b  = [&apos;a&apos;, &apos;b&apos;, &apos;c&apos;, &apos;d&apos;, &apos;e&apos;, &apos;f&apos;, &apos;h&apos;, &apos;i&apos;];

// Use the spread operator to concatenate
int[] array1 = [1, 2, 3];
int[] array2 = [4, 5, 6];
int[] array3 = [7, 8, 9];
int[] fullArray = [..array1, ..array2, ..array3]; // contents is [1, 2, 3, 4, 5, 6, 7, 8, 9]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 &lt;a href=&quot;https://devblogs.microsoft.com/dotnet/announcing-csharp-12&quot;&gt;Announcing C# 12&lt;/a&gt;中查看有关C#最新版本的更多信息。&lt;/p&gt;
&lt;h2&gt;.NET 8 support across Visual Studio family of tools&lt;/h2&gt;
&lt;p&gt;在最新的VS2017及以上可以使用.NET 8和C#12的特性&lt;/p&gt;
&lt;h3&gt;.NET 8更新的附加功能:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ASP.NET Core.&lt;/strong&gt; &lt;a href=&quot;https://devblogs.microsoft.com/dotnet/whats-new-with-identity-in-dotnet-8/&quot;&gt;Streamlines identity for single-page applications (SPA) and Blazor providing cookie-based authentication, pre-built APIs, token support, and a new identity UI.&lt;/a&gt; and &lt;a href=&quot;https://learn.microsoft.com/aspnet/core/release-notes/aspnetcore-8.0#minimal-apis&quot;&gt;enhances minimal APIs with form-binding, antiforgery support to protect against cross-site request forgery (XSRF/CSRF), and &lt;/a&gt;&lt;a href=&quot;https://learn.microsoft.com/aspnet/core/release-notes/aspnetcore-8.0#minimal-apis&quot;&gt;&lt;code&gt;asParameters&lt;/code&gt;&lt;/a&gt;&lt;a href=&quot;https://learn.microsoft.com/aspnet/core/release-notes/aspnetcore-8.0#minimal-apis&quot;&gt; support for parameter-binding with Open API definitions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ASP.NET Core tooling.&lt;/strong&gt; &lt;a href=&quot;https://devblogs.microsoft.com/dotnet/aspnet-core-route-tooling-dotnet-8/&quot;&gt;Route syntax highlighting, auto-completion, and analyzers to help you create Web APIs.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Entity Framework Core.&lt;/strong&gt; &lt;a href=&quot;https://devblogs.microsoft.com/dotnet/announcing-ef8-rc2/&quot;&gt;Provides new “complex types” as value objects, primitive collections, and SQL Server support for hierarchical data.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NuGet.&lt;/strong&gt; &lt;a href=&quot;https://learn.microsoft.com/nuget/concepts/auditing-packages&quot;&gt;Helps you audit your NuGet packages in projects and solutions for any known security vulnerabilities.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;.NET Runtime.&lt;/strong&gt; &lt;a href=&quot;https://devblogs.microsoft.com/dotnet/announcing-dotnet-8-rc1/#androidstripilafteraot-mode-on-android&quot;&gt;Brings a new AOT compilation mode for WebAssembly (WASM) and Android.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;.NET SDK.&lt;/strong&gt; &lt;a href=&quot;https://learn.microsoft.com/dotnet/core/whats-new/dotnet-8#net-sdk&quot;&gt;Revitalizes terminal build output and production-ready defaults.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WPF.&lt;/strong&gt; &lt;a href=&quot;https://devblogs.microsoft.com/dotnet/wpf-file-dialog-improvements-in-dotnet-8/&quot;&gt;Supports OpenFolderDialog&lt;/a&gt; and &lt;a href=&quot;https://devblogs.microsoft.com/dotnet/announcing-dotnet-8-rc1/#wpf-hardware-acceleration-in-rdp&quot;&gt;Enabled HW Acceleration in RDP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ARM64.&lt;/strong&gt; &lt;a href=&quot;https://devblogs.microsoft.com/dotnet/this-arm64-performance-in-dotnet-8/&quot;&gt;Significant feature enhancements and improved code quality for ARM64 platforms through collaboration with ARM engineers.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Debugging.&lt;/strong&gt; &lt;a href=&quot;https://devblogs.microsoft.com/dotnet/debugging-enhancements-in-dotnet-8/&quot;&gt;Displays debug summaries and provides simplified debug proxies for commonly used .NET types.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;System.Text.Json.&lt;/strong&gt; &lt;a href=&quot;https://devblogs.microsoft.com/dotnet/system-text-json-in-dotnet-8/&quot;&gt;Helps populate read-only members, customizes unmapped member handling, and improves Native AOT support.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;.NET Community Toolkit.&lt;/strong&gt; &lt;a href=&quot;https://devblogs.microsoft.com/dotnet/announcing-the-dotnet-community-toolkit-821/&quot;&gt;Accelerates building .NET libraries and applications while ensuring they are trim and AOT compatible (including the MVVM source generators!)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Azure.&lt;/strong&gt; &lt;a href=&quot;https://aka.ms/appservice-dotnet8&quot;&gt;Supports .NET 8 with Azure’s PaaS services like App Service for Windows and Linux, Static Web Apps, Azure Functions, and Azure Container Apps.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;F# 8.&lt;/strong&gt; &lt;a href=&quot;https://devblogs.microsoft.com/dotnet/announcing-fsharp-8/&quot;&gt;Includes significant language changes, new diagnostics, improvements in usability, and performance enhancements in project compilation, as well as upgrades to the FSharp.Core standard library.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What’s new in .NET 8.&lt;/strong&gt; &lt;a href=&quot;https://learn.microsoft.com/dotnet/core/whats-new/dotnet-8&quot;&gt;Check out our documentation for everything else!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Derick</author></item><item><title>Ethereum Development With Rust 2</title><link>https://blog.ithuo.net/posts/ethereum-development-with-rust-2/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/ethereum-development-with-rust-2/</guid><pubDate>Fri, 10 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;:::note&lt;/p&gt;
&lt;p&gt;This series of articles mainly uses Rust&apos;s ethers-rs to replicate the content of the book &quot;Ethereum Development with Go&quot;, so the title of this series is called &quot;Ethereum Development with Rust&quot;. It can be considered as a quick start tutorial for ethers-rs. Since the original book is already well-written, this series will focus more on replicating the code and will not explain too much about the related basic knowledge.&lt;/p&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;p&gt;Last time, we studied how to create various clients (Providers) with ethers-rs. This time, we will replicate the second chapter &quot;Accounts&quot; from &quot;Ethereum Development with Go&quot;.&lt;/p&gt;
&lt;p&gt;The &quot;Accounts&quot; chapter mainly includes the following content:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Account balance&lt;/li&gt;
&lt;li&gt;Account token balance&lt;/li&gt;
&lt;li&gt;Generating new wallets&lt;/li&gt;
&lt;li&gt;Keystore&lt;/li&gt;
&lt;li&gt;Address verification&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The dependencies used in this article are as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ethers = {version=&quot;2.0&quot;, features=[&quot;rustls&quot;, &quot;ws&quot;]}
tokio = {version=&quot;1&quot;, features=[&quot;full&quot;]}
eyre = &quot;0.6&quot;
hex = { package = &quot;const-hex&quot;, version = &quot;1.6&quot;, features = [&quot;hex&quot;] }
regex = &quot;1.10.2&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Account Balance&lt;/h3&gt;
&lt;p&gt;The accounts used here are the test accounts from Hardhat.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use ethers::prelude::*;
use ethers::utils;

const RPC_URL: &amp;amp;str = &quot;https://cloudflare-eth.com&quot;;

#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;(), Box&amp;lt;dyn std::error::Error&amp;gt;&amp;gt; {
    let provider = Provider::&amp;lt;Http&amp;gt;::try_from(RPC_URL)?;

    let balance = provider.get_balance(&quot;0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199&quot;, None).await?;
    println!(&quot;balance: {} ether&quot;, utils::format_ether(balance));
    println!(&quot;balance: {balance:?} wei&quot;);
    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The result type returned by &lt;code&gt;get_balance&lt;/code&gt; is &lt;code&gt;U256&lt;/code&gt;, and the default unit is wei. If we need to convert the format, we can use the provided utility library &lt;code&gt;utils&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Account Token Balance&lt;/h3&gt;
&lt;p&gt;Tokens in Ethereum generally refer to ERC20, so here we also show the code for getting the ERC20 token balance. Getting the balance of an ERC20 token is actually calling the &lt;code&gt;balanceOf&lt;/code&gt; method of its corresponding contract address.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use ethers::prelude::*;
use ethers::types::Address;
use ethers::utils;
use std::sync::Arc;

const RPC_URL: &amp;amp;str = &quot;https://cloudflare-eth.com&quot;;

#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;(), Box&amp;lt;dyn std::error::Error&amp;gt;&amp;gt; {
    let provider = Provider::&amp;lt;Http&amp;gt;::try_from(RPC_URL)?;

    let balance = provider.get_balance(&quot;0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199&quot;, None).await?;
    println!(&quot;balance: {} ether&quot;, utils::format_ether(balance));
    println!(&quot;balance: {balance:?} wei&quot;);

    // 通过宏直接生成一个IERC20的对象
    abigen!(
        IERC20,
        r#&quot;[
            function totalSupply() external view returns (uint256)
            function balanceOf(address account) external view returns (uint256)
            function transfer(address recipient, uint256 amount) external returns (bool)
            function allowance(address owner, address spender) external view returns (uint256)
            function approve(address spender, uint256 amount) external returns (bool)
            function transferFrom( address sender, address recipient, uint256 amount) external returns (bool)
            event Transfer(address indexed from, address indexed to, uint256 value)
            event Approval(address indexed owner, address indexed spender, uint256 value)
        ]&quot;#,
    );

    const ERC20_CONTRACT_ADDRESS: &amp;amp;str = &quot;0xEB1774bc66930a417A76Df89885CeE7c1A29f405&quot;;

    let erc20_address: Address = ERC20_CONTRACT_ADDRESS.parse()?;
    let erc20_account_address: Address = &quot;0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199&quot;.parse()?;
    let client = Arc::new(provider);
    let contract = IERC20::new(erc20_address, client);

    if let Ok(total_supply) = contract.total_supply().call().await {
        println!(&quot;ERC20 total supply is {total_supply:?}&quot;);
    }

    if let Ok(balance) = contract.balance_of(erc20_account_address).call().await {
        println!(&quot;ERC20 total supply is {balance:?}&quot;);
    }

    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rust has many advantages, one of the most prominent being macro programming. Rust&apos;s macros are much more powerful than metaprogramming in other languages. It can complete the compilation of macros at compile-time and generate corresponding code (although not visible), which allows for quick code hints and type safety. For example, the &lt;code&gt;abigen&lt;/code&gt; macro used here generates an object called &lt;code&gt;IERC20&lt;/code&gt;, which can create instances through the &lt;code&gt;new&lt;/code&gt; method, and this instance has methods corresponding to all the interfaces of ERC20.&lt;/p&gt;
&lt;p&gt;As for other tokens like ERC721, the method is similar.&lt;/p&gt;
&lt;h3&gt;Generating New Wallets&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ethers-rs&lt;/code&gt; supports multiple wallets, such as Private key, Ledger, Trezor, YubiHSM2, AWS KMS, etc., but this article mainly focuses on the first type.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// use the eyre crate for easy idiomatic error handling
use eyre::Result;
// use the ethers_core rand for rng
use ethers::core::rand::thread_rng;
// use the ethers_signers crate to manage LocalWallet and Signer
use ethers::signers::{LocalWallet, Signer, Wallet};
use ethers::types::H256;

// Use the `tokio::main` macro for using async on the main function
#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;()&amp;gt; {
    let prikey = [254, 159, 17, 110, 10, 156, 237, 11, 156, 168, 117, 202, 17, 248, 112, 124, 221, 128, 127, 28, 175, 158, 45, 115, 141, 192, 28, 164, 208, 166, 104, 250];

    println!(&quot;钱包的私有地址: {:?}&quot;, H256::from_slice(&amp;amp;prikey).to_string());
    // 创建随机钱包
    let wallet = LocalWallet::new(&amp;amp;mut thread_rng());
    println!(&quot;钱包私钥: {:?}&quot;, wallet.signer().to_bytes());
    println!(&quot;钱包公钥: {:?}&quot;, wallet.address());

    // 从指定字节数组中创建
    let wallet = Wallet::from_bytes(&amp;amp;prikey).unwrap();
    println!(&quot;钱包私钥: {:?}&quot;, wallet.signer().to_bytes());
    println!(&quot;钱包公钥: {:?}&quot;, wallet.address());

    let prikey = hex::decode(&quot;0xfe9f116e0a9ced0b9ca875ca11f8707cdd807f1caf9e2d738dc01ca4d0a668fa&quot;).unwrap();
    let wallet = Wallet::from_bytes(&amp;amp;prikey).unwrap();
    println!(&quot;钱包私钥: {:?}&quot;, wallet.signer().to_bytes());
    println!(&quot;钱包公钥: {:?}&quot;, wallet.address());

    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At its core, a blockchain wallet is just a 256-bit, 32-byte number, so possessing this number means having control over your wallet. However, even when stored in hexadecimal, this long string of 0s and 1s in binary has 64 characters, and there is no correlation between these characters, which is very unfriendly for human memory. Therefore, mnemonic phrases emerged, which can be mapped to your wallet (private key). Although this is an improvement, it is still not user-friendly, at least not in line with years of usage habits, leading to the emergence of various wallets.&lt;/p&gt;
&lt;p&gt;These wallets can be hardware or software-based. They encrypt your private key with a password. When you need to use your private key, you only need to use a password you set to recover the private key from the wallet, which is much simpler than remembering mnemonic phrases or the original private key.&lt;/p&gt;
&lt;h3&gt;Keystore&lt;/h3&gt;
&lt;p&gt;Similar to wallets, ethers-rs does not provide a similar feature, but wallets can be used as a substitute.&lt;/p&gt;
&lt;h3&gt;Address Verification&lt;/h3&gt;
&lt;p&gt;Address verification can be divided into two parts: whether the account address is valid and what type the account address belongs to.&lt;/p&gt;
&lt;h3&gt;Verifying Account Addresses&lt;/h3&gt;
&lt;p&gt;One pain point of using Rust is that the standard library is relatively lean, and many basic libraries found in other languages require third-party libraries in Rust, such as the regular expression library. Fortunately, the user experience of the package manager Cargo is good enough to alleviate this situation.&lt;/p&gt;
&lt;p&gt;The dependency for regular expressions is as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;regex = &quot;1.10.2”
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code for verification is as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;(), Box&amp;lt;dyn std::error::Error&amp;gt;&amp;gt; {
    let re = regex::Regex::new(r&quot;^0x[0-9a-fA-F]{40}$&quot;).expect(&quot;编译正则表达式失败.&quot;);

    // 结果为true
    println!(&quot;结果为{}\n&quot;, re.is_match(&quot;0x323b5d4c32345ced77393b3530b1eed0f346429d&quot;));
    // 结果为false
    println!(&quot;结果为{}\n&quot;, re.is_match(&quot;0xZYXb5d4c32345ced77393b3530b1eed0f346429d&quot;));
    println!(&quot;结果为{}\n&quot;, re.is_match(&quot;youerning.top&quot;));
    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ethereum&apos;s account address is not quite the same as Bitcoin, Bitcoin has certain verification rules, and Ethereum does not, as the above code does, so that this string as long as it is a legal 256-bit hexadecimal representation of the string is a legal account address.&lt;/p&gt;
&lt;h3&gt;Verify whether the address is a contract address or a general account address&lt;/h3&gt;
&lt;p&gt;There are two types of accounts in Ethereum, contract accounts and ordinary accounts (also known as external accounts), and the way to determine whether the account stores code is simple, because the contract saves the compiled code of the contract on its account object when it is created.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use ethers::prelude::*;

const RPC_URL: &amp;amp;str = &quot;https://cloudflare-eth.com&quot;;

#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;(), Box&amp;lt;dyn std::error::Error&amp;gt;&amp;gt; {
    let provider = Provider::&amp;lt;Http&amp;gt;::try_from(RPC_URL)?;

    // 地址也能传ens
    let code = provider.get_code(&quot;0xEB1774bc66930a417A76Df89885CeE7c1A29f405&quot;, None).await.expect(&quot;查询失败&quot;);
    if code.len() &amp;gt; 1 {
        println!(&quot;该地址是一个合约&quot;);
    } else {
        println!(&quot;该地址不是一个合约&quot;);
    }

    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Summary&lt;/h3&gt;
&lt;p&gt;This section mainly focuses on account creation and querying. Through ethers-rs, we can read multiple wallet types and create local wallets ourselves. With a wallet, we can sign transactions and messages, allowing other verifiers to confirm the legitimacy of the message by verifying the signature and corresponding account address.&lt;/p&gt;
&lt;p&gt;In ethers-rs, a wallet is primarily a wrapper around a signer object. The wallet binds this signer object with the blockchain ID (binding the message with the chain ID can avoid double-spending).&lt;/p&gt;
&lt;p&gt;Reference Links&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://goethereumbook.org/zh/%5B1%5D&quot;&gt;https://goethereumbook.org/zh/[1]&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://goethereumbook.org/en/%5B3%5D&quot;&gt;https://goethereumbook.org/en/[3]&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ethereum.org/en/developers/docs/programming-languages/rust/#rust-projects-and-tools%5B4%5D&quot;&gt;https://ethereum.org/en/developers/docs/programming-languages/rust/#rust-projects-and-tools[4]&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gakonst.com/ethers-rs&quot;&gt;https://gakonst.com/ethers-rs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.ethers.org/v5/&quot;&gt;https://docs.ethers.org/v5/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Derick</author></item><item><title>Notion博客折腾指南</title><link>https://blog.ithuo.net/posts/notion-blog-tinkering-guide/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/notion-blog-tinkering-guide/</guid><pubDate>Tue, 07 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;阿里的语雀和字节的飞书还有notion都是很好的写作平台，飞书的智能表格应该也是借鉴了notion的产品风格，而语雀前段时间在周一下午发生所有节点宕机8小时的P0事故，并且创始人已经入职飞书，这种亏损的团队出现如此严重的事故，一定会被边缘化，为了减少以后再出现故障，决定使用notion作为写作平台，并且备份到GitHub中，同时使用cloudflare部署站点。&lt;/p&gt;
&lt;h3&gt;用到了哪些工具&lt;/h3&gt;
&lt;p&gt;完整的工具链如下，除了elog和hexo剩下的工具都需要注册&lt;/p&gt;
&lt;p&gt;notion→slack→pipedream→elog→hexo→github→cloudflare→&lt;a href=&quot;https://blog.ithuo.net/&quot;&gt;最终博客&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;博客搭建教程&lt;/h3&gt;
&lt;h3&gt;第一步&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;单独注册完这些工具后，先看一遍elog官方文档，因为是使用&lt;a href=&quot;https://www.notion.com/my-integrations&quot;&gt;elog&lt;/a&gt;作为同步工具，承上启下，所以重点会在&lt;strong&gt;elog&lt;/strong&gt;上&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;第二步&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;注册notion，并复制 &lt;a href=&quot;https://1874.notion.site/09ff9e1e141744c6af0a1f69d2a3d834?v=a09065f9266446afa745b475044daca6&quot;&gt;elog-notion-template | 表格&lt;/a&gt; 数据库到空间内，记录数据库ID。创建integrations &lt;a href=&quot;https://www.notion.com/my-integrations&quot;&gt;https://www.notion.com/my-integrations&lt;/a&gt; 并集成到刚复制的这个模板中，记录Integrations的Secrets当作同步Token。(&lt;strong&gt;注意&lt;/strong&gt;两个关键要素&lt;strong&gt;NOTION_DATABASE_ID&lt;/strong&gt;和&lt;strong&gt;NOTION_TOKEN&lt;/strong&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/91065cef4b9ef723e774da44be6a1d62.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/c148d09633a0d7f16be2c679e02d2d97.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;第三步&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;注册slack，添加notion应用，与notion进行关联，并且配置小闪电（自动程序）用于监听文档状态，例如当有文档status设置为&lt;code&gt;已发布&lt;/code&gt;，则给slack发送消息&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/1376acc03ccd5250565d411b26ad747b.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/35e672da49d0e3ec67ef6d2ff4d2a4de.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/465a85d7417abe821efe00c52627aa2a.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;第四步&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;注册pipedream，添加自动化脚本&lt;code&gt;trigger&lt;/code&gt;用于监听slack的消息，并通知GitHub Workflow Action进行打包发布，创建&lt;code&gt;trigger&lt;/code&gt;和&lt;code&gt;http&lt;/code&gt;调用通知。需要&lt;strong&gt;提前&lt;/strong&gt;在Github创建存储仓库并生成**&lt;code&gt;Github Token&lt;/code&gt;**&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/3bf5f6b2ad2113ca3b83255dd0ed3508.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/035a7df1406cf27708a3499b19bdef31.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用elog提供的&lt;code&gt;vercel-severless&lt;/code&gt;服务可以很方便的调用GitHub的&lt;code&gt;Deploy API&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;https://serverless-api-elog.vercel.app/api/github?user=cyolc932&amp;amp;repo=elog&amp;amp;event_type=deploy&amp;amp;token=xxx
//例如你的github用户名，仓库名称，部署名称以及github的token
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;如果点击Test调用Github API没有出现&lt;code&gt;Success&lt;/code&gt;，需要检查&lt;code&gt;Github Token&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/60ed25ab468a5ed79e32c2b2f5dfd885.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;第五步&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;使用&lt;a href=&quot;https://hexo.io/&quot;&gt;&lt;strong&gt;Hexo 6.3+&lt;/strong&gt;&lt;/a&gt; 网站皮肤选择 &lt;a href=&quot;https://aurora.tridiamond.tech/en/guide/getting-started.html&quot;&gt;Hexo Aurora&lt;/a&gt;，安装hexo和配置皮肤在此不在赘述&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;第六步&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;在安装好hexo的项目环境中通过npm安装elog&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;# 使用 npm 安装 CLI
npm install @elog/cli -g

# 使用 yarn 安装 CLI
yarn global add @elog/cli

# 使用 pnpm 安装 CLI
pnpm install @elog/cli -g

# 安装指定版本
npm install @elog/cli@0.9.0 -g

# 也可使用 npx 运行 elog 的所有命令：将本文档使用 elog 命令的地方换成 npx @elog/cli
# 例如
# 初始化 elog 配置文件
npx @elog/cli init
# 本地同步命令
npx @elog/cli sync -e .elog.env
# 清除本地缓存
npx @elog/cli clean
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;在代码路径中初始化elog后，会出现这些elog开头的配置文件，使用哪个平台就配置哪个，比如我选择的是&lt;code&gt;notion+GitHub&lt;/code&gt;，注意将&lt;code&gt;.elog.env&lt;/code&gt;加入忽略文件，避免泄露关键信息&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/f442f9dfcf76156749143d9b2c58f19d.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;配置&lt;code&gt;.elog.env&lt;/code&gt;后，继续配置&lt;code&gt;elog.config.js&lt;/code&gt;，关键配置如下&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;module.exports = {
  write: {
    platform: &apos;notion&apos;,
    notion: {
      token: process.env.NOTION_TOKEN,
      databaseId: process.env.NOTION_DATABASE_ID,
      limit: 3,
      filter: {
        and: [
          {
            property: &apos;status&apos;,
            select: { equals: &apos;Published&apos; }
          },
          {
            property: &apos;type&apos;,
            select: { equals: &apos;Post&apos; }
          },
        ]
      },
      sorts: false, // [{timestamp: &apos;created_time&apos;, direction: &apos;descending&apos;}],
      catalog:  {
        enable: true,
        property: &quot;date&quot;,
      },
    },
  },
  deploy: {
    platform: &apos;local&apos;,
    local: {
      outputDir: &apos;./article&apos;,
      filename: &apos;title&apos;,
      format: &apos;matter-markdown&apos;,
      catalog: true,
      formatExt: &apos;./formatext.js&apos;,
    },
  },
  image: {
    enable: true,
    platform: &apos;local&apos;,// 注意， 如果放在local，会导致cloud flare无法显示图片，建议使用图床
    local: {
      outputDir: &apos;./images&apos;,
      prefixKey: &apos;../../images&apos;,
    }
  },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;如果使用了&lt;code&gt;hexo&lt;/code&gt;，需要对&lt;code&gt;markdown&lt;/code&gt;做一些格式处理，在代码根目录添加&lt;code&gt;formatext.js&lt;/code&gt;，代码如下&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;const { matterMarkdownAdapter } = require(&quot;@elog/plugin-adapter&quot;);

/**
 * 自定义文档处理器
 * @param {DocDetail} doc doc的类型定义为 DocDetail
 * @return {string} 返回处理后的文档内容字符串
 */
const format = (doc) =&amp;gt; {
  if (doc.properties) {
    let properties = doc.properties

    for (var key in properties) {
      if (properties.hasOwnProperty(key) &amp;amp;&amp;amp; properties[key] === &quot;&quot;) {
        delete properties[key];
      }
    }
  }

  return matterMarkdownAdapter(doc);
};

module.exports = {
  format,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;现在&lt;code&gt;elog&lt;/code&gt;环节配置结束，使用命令验证是否可以正常同步&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/6a0614f7cd8a527b26b83d067f11dbc1.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;第七步&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;配置&lt;code&gt;GitHub&lt;/code&gt;环境变量和&lt;code&gt;Github Action&lt;/code&gt; ，在你创建的GitHub存储库中点击&lt;code&gt;Settings&lt;/code&gt;如下图步骤&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/24d09b3e4e2791893943c4afad801c7a.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;第八步&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;使用仓库的&lt;code&gt;Github Action&lt;/code&gt;接收&lt;code&gt;pipedream&lt;/code&gt;的调用，并通过&lt;code&gt;elog&lt;/code&gt;同步&lt;code&gt;notion&lt;/code&gt;数据转换成&lt;code&gt;markdown&lt;/code&gt;并提交。&lt;code&gt;Action&lt;/code&gt;代码如下:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;name: Notion-Action-MD

on:
  push:
    branches:
      - main
  # 手动运行
  workflow_dispatch:
  # 允许外部仓库事件触发
  repository_dispatch:
    types:
      - deploy
  schedule:
    - cron: &quot;0 * * * *&quot;

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: 检出代码库
        uses: actions/checkout@v2

			- name: Install dependencies
        run: npm install

      - name: 安装 @elog/cli
        run: npm install @elog/cli -g
			
			- name: 安装 @elog/plugin-adapter
        run: npm install @elog/plugin-adapter -g

      - name: 执行 elog sync
        env:
          NOTION_TOKEN: ${{ secrets.NOTION_TOKEN }}
          NOTION_DATABASE_ID: ${{ secrets.NOTION_DATABASE_ID }}
          COS_SECRET_ID: ${{ secrets.COS_SECRET_ID }}
          COS_SECRET_KEY: ${{ secrets.COS_SECRET_KEY }}
          COS_BUCKET: ${{ secrets.COS_BUCKET }}
          COS_REGION: ${{ secrets.COS_REGION }}
        run: |
          elog sync

      - name: 配置Git用户名邮箱
        run: |
          git config --global user.name &quot;user&quot;
          git config --global user.email &quot;123@666.com&quot;

      - name: 提交拉取的文章到GitHub仓库
        run: |
          echo `date +&quot;%Y-%m-%d %H:%M:%S&quot;` begin &amp;gt; time.txt
          git add .
          git commit -m &quot;Refresh elog.cache.json&quot; -a

      - name: 推送文章到仓库
        uses: ad-m/github-push-action@master
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}

      - name: Action保活
        uses: gautamkrishnar/keepalive-workflow@master
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;第九步&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;注册&lt;code&gt;Cloud Flare&lt;/code&gt;或者&lt;code&gt;Vercel&lt;/code&gt;作为站点托管平台，如果仅仅是备份目的，在第8步完成就结束了&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/01c42578db05e6c3beb7ee46791db36a.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在&lt;code&gt;CloudFlare&lt;/code&gt;创建&lt;code&gt;pages&lt;/code&gt;应用，连接你的&lt;code&gt;GitHub&lt;/code&gt;仓库，构建命令如下，如果有域名可以使用子域名映射进来，比如我的将&lt;code&gt;blog&lt;/code&gt;映射到此&lt;code&gt;pages&lt;/code&gt;下。添加完成之后，每次&lt;code&gt;GitHub&lt;/code&gt;提交后&lt;code&gt;CloudFlare&lt;/code&gt;就会拉取代码，重新构建。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/e46aa3da38d0e7dc0e75007ea28d6999.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;第十步&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;在上一步我们已经结束了所有的配置，确实有点繁琐，希望以后可以优化成开箱即用的产品，回顾一下，本次做的工具调用链如下：&lt;/li&gt;
&lt;li&gt;[ ] 通过notion作为创作平台编写文章，文章到&lt;code&gt;已发布&lt;/code&gt; 状态就给slack发送消息通知&lt;/li&gt;
&lt;li&gt;[ ] slack收到消息通知后，pipedream也在slack的notion频道偷听，要开始发布内容了&lt;/li&gt;
&lt;li&gt;[ ] pipedream听到消息就通过vercel的severless以HTTP方式调用GitHub的Deploy API&lt;/li&gt;
&lt;li&gt;[ ] GitHub的deploy api收到消息就通知仓库的Github Action起来干活，安装elog环境，读取Github的环境变量，执行elog命令拉取notion数据，生成为markdown格式，提交到GitHub 仓库中&lt;/li&gt;
&lt;li&gt;[ ] cloud flare的pages应用监听到链接的GitHub仓库有新的提交内容，就调用GitHub API拉取仓库数据，然后进行hexo编译和npm打包生成静态页面，并悄悄地部署在pages节点中。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;异常指南&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;notion链接到slack中发送消息失败，多拖动几次，slack并非实时接收notion的变更消息&lt;/li&gt;
&lt;li&gt;pipedream中通过HTTP调用GitHub API失败，检查token，首次部署建议多开放一些权限&lt;/li&gt;
&lt;li&gt;elog同步数据失败，检查notion数据库ID和token&lt;/li&gt;
&lt;li&gt;GitHub action运行失败，检查环境变量，&lt;a href=&quot;https://docs.github.com/zh/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idoutputs&quot;&gt;GitHub Actions 的工作流语法 - GitHub 文档&lt;/a&gt; 并且参考 &lt;a href=&quot;https://github.com/ad-m/github-push-action/blob/master/action.yml&quot;&gt;github-push-action/action.yml at master · ad-m/github-push-action&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;elog同步时将notion内容转换为markdown格式还有一些适配问题，需要发布后重新检查下格式&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;参考文章&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://darkreunion.tech/article/backup-notion-to-github?giscus=5b1855710a9073bbb30d3264lzzxL%2FY5boFMZEtzfT2uvrsTkpO815dTCl%2BcFCsI%2FwZTnmkVo1SjQB2CllPRsX9pkEFoeAZ77J%2FviSyilYpOqYYX%2FGm9rbQWTk0T8J0bqUaJf4Q%2BJl9YANenxts%3D&quot;&gt;备份 Notion 文档到 Github | 某中二的黑科技研究中心 (darkreunion.tech)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://matrixcore.top/article/elog&quot;&gt;[跨域协同] elog+notion实现md优雅备份 | MatrixCore&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bmqy.net/2651.html?highlight=elog&quot;&gt;集成Elog使用notion数据库 | 北门清燕 (bmqy.net)&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;工具平台&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.notion.so/&quot;&gt;https://www.notion.so/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.slack.com/&quot;&gt;https://app.slack.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://pipedream.com/&quot;&gt;https://pipedream.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://hexo.io/zh-cn/&quot;&gt;Hexo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://aurora.tridiamond.tech/en/guide/getting-started.html&quot;&gt;Getting started | Hexo Aurora Docs (tridiamond.tech)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://dash.cloudflare.com/&quot;&gt;https://dash.cloudflare.com/&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;官方文档&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://elog.1874.cool/notion/start&quot;&gt;快速开始 | Elog (1874.cool)&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;文件存储&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.upyun.com/products/file-storage&quot;&gt;云存储 - 大规模文件数据存储 - 又拍云 (upyun.com)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.aliyun.com/product/oss&quot;&gt;对象存储 OSS_云存储服务_企业数据管理_存储-阿里云 (aliyun.com)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://cloud.tencent.com/product/cos&quot;&gt;对象存储数据处理_COS数据处理_数据处理方案-腾讯云 (tencent.com)&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Ethereum Development with rust 1</title><link>https://blog.ithuo.net/posts/ethereum-development-with-rust-1/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/ethereum-development-with-rust-1/</guid><pubDate>Sun, 05 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The intention is that if you are already somewhat familiar with Ethereum and Rust, but are unsure about how to combine the two, then this book is a good starting point - adapted from &quot;Ethereum Development with Go&quot;&lt;/p&gt;
&lt;p&gt;Ethereum development can generally be divided into two categories:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;On-chain development, which is developing smart contracts, typically using the Solidity programming language.&lt;/li&gt;
&lt;li&gt;Off-chain development, which involves interacting with the blockchain, such as reading block data, sending transactions, and interacting with contracts.
There is actually a third type, which is sidechain or layer 2 development.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This series of articles will mainly focus on the second type.&lt;/p&gt;
&lt;p&gt;The dependencies used in this article are as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ethers = {version=&quot;2.0&quot;, features=[&quot;rusttls&quot;, &quot;ws&quot;]}
tokio = {version=&quot;1&quot;, features=[&quot;full&quot;]}
eyre = &quot;0.6&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Quick Start&lt;/h3&gt;
&lt;p&gt;The concepts of ethers-rs and go-ethereum are somewhat different; the former uses the term &quot;provider,&quot; while the latter uses &quot;client.&quot; The concept of a provider is likely inherited from ethers.js, so if you have experience with ethers.js, you should be quite familiar with many of the concepts in ethers-rs.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use ethers::prelude::*;

const RPC_URL: &amp;amp;str = &quot;https://cloudflare-eth.com&quot;;

#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;(), Box&amp;lt;dyn std::error::Error&amp;gt;&amp;gt; {
    let provider = Provider::&amp;lt;Http&amp;gt;::try_from(RPC_URL)?;
    let block_number = provider.get_block_number().await?;
    println!(&quot;当前节点区块高度: {block_number}&quot;);
    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Client/Provider&lt;/h3&gt;
&lt;p&gt;To interact with the Ethereum network, it&apos;s essential to first connect to a node within the network. We have many options for nodes, broadly categorized into public (external) and private. Below are some public free interfaces (all require registration), while private ones naturally require setting up on your own, which won&apos;t be elaborated here.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Etherscan&lt;/li&gt;
&lt;li&gt;INFURA&lt;/li&gt;
&lt;li&gt;Alchemy&lt;/li&gt;
&lt;li&gt;Pocket Gateway&lt;/li&gt;
&lt;li&gt;Ankr&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For specific advantages and disadvantages and detailed comparisons, refer to: &lt;a href=&quot;https://docs.ethers.org/v5/api-keys/&quot;&gt;https://docs.ethers.org/v5/api-keys/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If the data you&apos;re querying is relatively simple, such as basic blockchain data (block hash, transaction list, event list), then you can directly use free public interfaces like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://cloudflare-eth.com/&quot;&gt;https://cloudflare-eth.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;wss://cloudflare-eth.com&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The main difference above lies in the application protocol used. If we need to perform listening operations, we need to use the wss (Websocket) protocol.&lt;/p&gt;
&lt;p&gt;Once we&apos;ve decided on the node to connect to, we can proceed to connect using code.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use ethers::prelude::*;

const HTTP_RPC_URL: &amp;amp;str = &quot;https://cloudflare-eth.com&quot;;
const WEBSOCKET_RPC_URL: &amp;amp;str = &quot;wss://cloudflare-eth.com&quot;;

#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;(), Box&amp;lt;dyn std::error::Error&amp;gt;&amp;gt; {
    let provider = Provider::&amp;lt;Http&amp;gt;::try_from(HTTP_RPC_URL)?;
    let block_number = provider.get_block_number().await?;
    println!(&quot;current block number: {block_number}&quot;);
    let provider = Provider::&amp;lt;Ws&amp;gt;::connect(WEBSOCKET_RPC_URL).await?;
    let block_number = provider.get_block_number().await?;
    println!(&quot;current block number: {block_number}&quot;);
    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For local connections, a more efficient connection method is IPC (Inter-Process Communication) connection.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use ethers::providers::Provider;

const IPC_RPC_URL: &amp;amp;str = &quot;~/.ethereum/geth.ipc&quot;;

#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;(), Box&amp;lt;dyn std::error::Error&amp;gt;&amp;gt; {
    let provider = Provider::connect_ipc(IPC_RPC_URL)?;
    let block_number = provider.get_block_number().await?;
    println!(&quot;current block number: {block_number}&quot;);
    Ok(())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point, we have a client that can access the Ethereum network, but the network is not always reliable, such as when there are network outages or reconnections. Therefore, we have to deal with these trivial issues, which are generally annoying to handle. Fortunately, ethers-rs has already done this tedious work for us. It provides many additional wrappers, such as Quorum, Retry, and RW, whose functions are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Quorum: When created, it sets multiple request backends, and only returns a result when more than 50% of the outcomes are the same. For example, if three nodes are set during creation and they return, then the Quorum type client will return 1, even if the result 3 is returned first.&lt;/li&gt;
&lt;li&gt;Retry: This should be easy to understand; it&apos;s simply retrying. We can set the maximum number of retries and the initial value for fallback.&lt;/li&gt;
&lt;li&gt;RW: This is read-write separation, one for reading and one for writing, which can also improve performance to some extent.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For specific example code, refer to the official documentation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://gakonst.com/ethers-rs/providers/quorum.html&quot;&gt;https://gakonst.com/ethers-rs/providers/quorum.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gakonst.com/ethers-rs/providers/retry.html&quot;&gt;https://gakonst.com/ethers-rs/providers/retry.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gakonst.com/ethers-rs/providers/rw.html&quot;&gt;https://gakonst.com/ethers-rs/providers/rw.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition, ethers-rs also provides Mock for testing, as well as custom extensions.&lt;/p&gt;
&lt;h3&gt;Summary:&lt;/h3&gt;
&lt;p&gt;This article simply lists the various ways to build clients with ethers-rs, corresponding to the first chapter of &quot;Ethereum Development with Go&quot;. Unlike go-ethereum, ethers-rs provides many additional wrapper types, so you don&apos;t have to deal with retries, data consistency (to a certain extent of data consistency, which requires multiple nodes chosen for Quorum), and some other common issues. Through these wrapper types, we can write safer and more efficient code.&lt;/p&gt;
&lt;p&gt;Reference Links:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://goethereumbook.org/zh/&quot;&gt;https://goethereumbook.org/zh/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://goethereumbook.org/en/&quot;&gt;https://goethereumbook.org/en/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ethereum.org/en/developers/docs/programming-languages/rust/#rust-projects-and-tools&quot;&gt;https://ethereum.org/en/developers/docs/programming-languages/rust/#rust-projects-and-tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gakonst.com/ethers-rs&quot;&gt;https://gakonst.com/ethers-rs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.ethers.org/v5/&quot;&gt;https://docs.ethers.org/v5/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Derick</author></item><item><title>如何使用Foundry开发并部署一个ERC20智能合约</title><link>https://blog.ithuo.net/posts/how-to-develop-and-deploy-an-erc20-smart-contract-using-foundry/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/how-to-develop-and-deploy-an-erc20-smart-contract-using-foundry/</guid><pubDate>Thu, 02 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;引言&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;ERC20 是一种基于以太坊的标准代币，它遵循了一组规则，定义了代币的名称，符号，小数位数，总供应量，余额，转账，授权等功能。ERC20 代币可以用来表示各种价值，例如货币，积分，股份，证券等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Foundry&lt;/strong&gt; 是一种基于 &lt;code&gt;Rust&lt;/code&gt; 的智能合约开发工具链，它可以让您用 &lt;code&gt;Solidity&lt;/code&gt; 语言编写，编译，测试，部署，和交互以太坊上的智能合约。Foundry 提供了三个主要的工具：&lt;strong&gt;forge&lt;/strong&gt;，&lt;strong&gt;cast&lt;/strong&gt;，和 &lt;strong&gt;anvil&lt;/strong&gt;，分别用于合约的编译，交互，和本地网络的构建。&lt;/li&gt;
&lt;li&gt;下面用一个简单的案例讲解使用 Foundry 开发并部署 ERC20 代币，注意遵循以下步骤：&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;安装Foundry&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;执行下面命令安装 Foundry。不要直接使用Windows开发，Windows用户必须使用WSL2，参考 Foundry 的&lt;a href=&quot;https://book.getfoundry.sh/getting-started/installation&quot;&gt;官方文档&lt;/a&gt;来安装 。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;// 下载安装Foundry
curl -L https://foundry.paradigm.xyz | bash
// 更新Foundry
foundryup
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;使用Foundry创建一个新的项目&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;使用 &lt;code&gt;forge init&lt;/code&gt; 命令来创建一个新的项目，指定项目的名称和模板。&lt;/p&gt;
&lt;p&gt;例如，您可以运行以下命令来创建一个名为 &lt;code&gt;MyERC20&lt;/code&gt; 的项目，使用一个包含了 ERC20 合约的模板：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;forge init --template https://github.com/FrankieIsLost/forge-template MyERC20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样就可以在 &lt;code&gt;MyERC20&lt;/code&gt; 文件夹中找到一个名为 &lt;code&gt;MyERC20.sol&lt;/code&gt; 的合约文件，以及一个名为 &lt;code&gt;MyERC20.t.sol&lt;/code&gt; 的测试文件。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;编写 ERC20 合约&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;可以根据需求，修改 &lt;code&gt;MyERC20.sol&lt;/code&gt; 文件中的合约代码，设置代币的名称，符号，小数位数，总供应量等参数。您也可以添加一些自定义的逻辑或事件，只要保证您的合约遵循了 ERC20 的标准接口。可以参考以下代码来编写一个简单的 ERC20 合约：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity &amp;gt;=0.8.0;

import {ERC20} from &quot;openzeppelin-contracts/token/ERC20/ERC20.sol&quot;;

contract MyERC20 is ERC20 {
    // 设置代币的名称，符号，和小数位数
    constructor() ERC20(&quot;My Token&quot;, &quot;MYT&quot;) {
        // 设置代币的总供应量为 10000 个，并分配给部署者
        _mint(msg.sender, 10000 * 10 ** decimals());
    }

    // 添加一个自定义的事件，用于记录代币的销毁
    event Burn(address indexed from, uint256 amount);

    // 添加一个自定义的函数，用于销毁代币
    function burn(uint256 amount) public {
        // 调用内部的 _burn 函数，从发送者的地址中销毁指定数量的代币
        _burn(msg.sender, amount);
        // 触发 Burn 事件
        emit Burn(msg.sender, amount);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;测试 ERC20 合约&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;您可以使用 &lt;code&gt;forge test&lt;/code&gt; 命令来运行 &lt;code&gt;MyERC20.t.sol&lt;/code&gt; 文件中的测试代码，检查您的合约是否符合预期的功能和性能。您可以使用 Solidity 语言来编写测试代码，使用 &lt;code&gt;DSTest&lt;/code&gt; 库来提供断言和异常处理，使用 &lt;code&gt;console&lt;/code&gt; 库来打印日志，使用 &lt;code&gt;vm&lt;/code&gt; 库来操作 EVM 的状态。您也可以使用 &lt;code&gt;forge fuzz&lt;/code&gt; 命令来进行模糊测试，检查您的合约是否存在潜在的漏洞或错误。&lt;/p&gt;
&lt;p&gt;例如，您可以参考以下代码来编写一个简单的测试用例，检查代币的转账和销毁功能：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity &amp;gt;=0.8.0;

import {console} from &quot;forge-std/console.sol&quot;;
import {stdStorage, StdStorage, Test} from &quot;forge-std/Test.sol&quot;;

import {MyERC20} from &quot;../MyERC20.sol&quot;;

contract MyERC20Test is MyERC20, Test {
    // 设置两个测试账户
    address alice = address(0x123);
    address bob = address(0x456);

    // 在每个测试用例之前，给测试账户分配一些代币
    function setUp() public override {
        _mint(alice, 1000 * 10 ** decimals());
        _mint(bob, 500 * 10 ** decimals());
    }

    // 测试代币的转账功能
    function testTransfer() public {
        // 打印日志
        console.log(&quot;Testing transfer&quot;);
        // 记录转账前的余额
        uint256 aliceBalanceBefore = balanceOf(alice);
        uint256 bobBalanceBefore = balanceOf(bob);
        // 以 Alice 的身份，向 Bob 转账 100 个代币
        vm.prank(alice);
        transfer(bob, 100 * 10 ** decimals());
        // 记录转账后的余额
        uint256 aliceBalanceAfter = balanceOf(alice);
        uint256 bobBalanceAfter = balanceOf(bob);
        // 检查余额是否正确变化
        assertEq(aliceBalanceAfter, aliceBalanceBefore - 100 * 10 ** decimals(), &quot;Alice balance should decrease&quot;);
        assertEq(bobBalanceAfter, bobBalanceBefore + 100 * 10 ** decimals(), &quot;Bob balance should increase&quot;);
    }

    // 测试代币的销毁功能
    function testBurn() public {
        // 打印日志
        console.log(&quot;Testing burn&quot;);
        // 记录销毁前的余额和总供应量
        uint256 aliceBalanceBefore = balanceOf(alice);
        uint256 totalSupplyBefore = totalSupply();
        // 以 Alice 的身份，销毁 50 个代币
        vm.prank(alice);
        burn(50 * 10 ** decimals());
        // 记录销毁后的余额和总供应量
        uint256 aliceBalanceAfter = balanceOf(alice);
        uint256 totalSupplyAfter = totalSupply();
        // 检查余额和总供应量是否正确变化
        assertEq(aliceBalanceAfter, aliceBalanceBefore - 50 * 10 ** decimals(), &quot;Alice balance should decrease&quot;);
        assertEq(totalSupplyAfter, totalSupplyBefore - 50 * 10 ** decimals(), &quot;Total supply should decrease&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;部署 ERC20 合约&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;您可以使用 &lt;code&gt;forge create&lt;/code&gt; 命令来将您的合约部署到指定的网络，例如主网或测试网。您需要配置部署网络的 RPC URL，以及部署合约的账户的私钥。您也可以使用 &lt;code&gt;cast&lt;/code&gt; 工具来与部署后的合约进行交互，调用它的函数或查询它的状态。&lt;/p&gt;
&lt;p&gt;运行以下命令来将您的合约部署到 Goerli 测试网：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;forge create --rpc-url &amp;lt;your_rpc_url&amp;gt; --private-key &amp;lt;your_private_key&amp;gt; src/MyERC20.sol:MyERC20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样就可以得到合约的部署者地址，合约的地址，和交易的哈希。您可以使用以下命令来与合约进行交互：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cast call --rpc-url &amp;lt;your_rpc_url&amp;gt; --private-key &amp;lt;your_private_key&amp;gt; &amp;lt;contract_address&amp;gt; balanceOf &amp;lt;account_address&amp;gt;
cast send --rpc-url &amp;lt;your_rpc_url&amp;gt; --private-key &amp;lt;your_private_key&amp;gt; &amp;lt;contract_address&amp;gt; transfer &amp;lt;recipient_address&amp;gt; &amp;lt;amount&amp;gt;
cast send --rpc-url &amp;lt;your_rpc_url&amp;gt; --private-key &amp;lt;your_private_key&amp;gt; &amp;lt;contract_address&amp;gt; burn &amp;lt;amount&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;部署在本地环境&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在合约正式部署前通常需要在本地进行充分的测试，交互验证，需要启动&lt;code&gt;anvil&lt;/code&gt; 服务，默认RPC-URL地址为&lt;code&gt;127.0.0.1:8545&lt;/code&gt; ,开启后可以将合约部署在本地进行测试验证。&lt;/p&gt;
&lt;h3&gt;备注：&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;RPC_URL可以去&lt;a href=&quot;https://www.infura.io/zh&quot;&gt;infura&lt;/a&gt;或者&lt;a href=&quot;https://www.alchemy.com/&quot;&gt;alchemy&lt;/a&gt; 申请&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;private-key&lt;/strong&gt;是钱包地址的私钥&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://etherscan.io/&quot;&gt;etherscan.io&lt;/a&gt; 申请key，方便校验合约&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sepolia.dev/&quot;&gt;[测试网] sepolia&lt;/a&gt;  领取测试水龙头(代币)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://goerli.net/&quot;&gt;[测试网] goerli&lt;/a&gt;   领取测试水龙头(代币)&lt;/li&gt;
&lt;li&gt;血泪教训：Windows用户一定直接开启WSL2，通过&lt;strong&gt;VS Code&lt;/strong&gt; 进行Remote开发，不然你将浪费大量时间踩坑。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.ithuo.net/post/2023-11-01%2FWSL2%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE&quot;&gt;WSL2环境配置 | Think Blog (ithuo.net)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Derick</author></item><item><title>WSL2环境配置</title><link>https://blog.ithuo.net/posts/wsl2-environment-configuration/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/wsl2-environment-configuration/</guid><pubDate>Wed, 01 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;引言&lt;/h3&gt;
&lt;p&gt;WSL2是Windows系统上的Linux子系统的一个新版本，它可以让用户在Windows上运行Linux环境和应用程序，而不需要安装虚拟机或双系统。WSL2使用虚拟化技术在轻量级虚拟机中运行Linux内核，提供了更好的文件系统性能和更完全的系统调用兼容性。WSL2还支持运行图形应用程序和GPU加速等功能。WSL2可以实现文件、指令和网络的互通，方便用户在Windows和Linux之间切换和操作。WSL2是一个非常强大和灵活的工具，可以让用户享受Linux的优势，同时保留了Windows的体验。&lt;/p&gt;
&lt;h3&gt;启用Hyper-V和适用于Linux的Windows子系统&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/958e2c133e897b2967b8dcaf80884469.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/2202ae1086f8281fe1dac5ced6c669bd.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;重启电脑&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/401e9ddc9124a05308c0f71787170391.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;打开配置后，会在开始菜单新增一个Ubuntu的图标，单击之后会进入安装环节&lt;/li&gt;
&lt;li&gt;如果没有Ubuntu的图标就再power shell中执行命令 &lt;code&gt;wsl --install&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;【开始菜单】点击Ubuntu图标&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/0c4b77409fd9111208ebd51fae270711.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;设置登陆账户密码&lt;/h3&gt;
&lt;p&gt;安装结束后会提示创建账户。已经有了默认的root账户，需要重新配置一个其他账户&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/b6f58b3a6f2ffa11571b30fad0f9d8b3.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;wsl -l -o&lt;/code&gt; 查看可以安装哪些Linux发行版&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/4db67c17334e455b9664de72a712a3cb.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;默认安装Ubuntu发行版，目前时Ubuntu2204&lt;/li&gt;
&lt;li&gt;若要更改安装的发行版，请输入：&lt;code&gt;wsl --install -d &amp;lt;Distribution Name&amp;gt;&lt;/code&gt;。 将 &lt;code&gt;&amp;lt;Distribution Name&amp;gt;&lt;/code&gt; 替换为要安装的发行版的名称。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Q: 如果安装wsl2时出现error code is 0x8007019e&lt;/h3&gt;
&lt;p&gt;重新检查是否开启hyper-V和Linux 在Windows的子系统，然后执行如下命令，重装默认系统&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;wsl --install
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
wsl --set-default-version 2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;自定义配置&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# Settings apply across all Linux distros running on WSL 2
[wsl2]
networkingMode=mirrored
dhcp=true
dnsTunneling=true

# Limits VM memory to use no more than 4 GB, this can be set as whole numbers using GB or MB
memory=4GB 

# Sets the VM to use two virtual processors
processors=4

# Specify a custom Linux kernel to use with your installed distros. The default kernel used can be found at https://github.com/microsoft/WSL2-Linux-Kernel
#kernel=D:\\Drivers\\WSL\\mykernel

# Sets additional kernel parameters, in this case enabling older Linux base images such as Centos 6
#kernelCommandLine = vsyscall=emulate

# Sets amount of swap storage space to 8GB, default is 25% of available RAM
swap=4GB

# Sets swapfile path location, default is %USERPROFILE%\AppData\Local\Temp\swap.vhdx
swapfile=D:\\Drivers\\WSL\\wsl-swap.vhdx

# Disable page reporting so WSL retains all allocated memory claimed from Windows and releases none back when free
#pageReporting=false

# Turn on default connection to bind WSL 2 localhost to Windows localhost
#localhostforwarding=true

# Disables nested virtualization
#nestedVirtualization=false

# Turns on output console showing contents of dmesg when opening a WSL 2 distro for debugging
#debugConsole=true

# Enable experimental features
[experimental]
autoProxy=true
bestEffortDnsParsing=true
useWindowsDnsCache=false
#   autoMemoryReclaim=gradual
#   networkingMode=mirrored
#   dnsTunneling=true
#   #firewall=false
#   autoProxy=true
#   sparseVhd=true
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;设置WSL最佳实践&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/zh-cn/windows/wsl/setup/environment#set-up-your-linux-username-and-password&quot;&gt;设置 WSL 开发环境 | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/zh-cn/windows/wsl/tutorials/wsl-vscode&quot;&gt;开始通过 WSL 使用 VS Code | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://code.visualstudio.com/docs/remote/wsl-tutorial&quot;&gt;Work in Windows Subsystem for Linux with Visual Studio Code&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>软件研发过程项目管理制度V5.0</title><link>https://blog.ithuo.net/posts/software-development-project-management-process-v5-guide/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/software-development-project-management-process-v5-guide/</guid><pubDate>Thu, 07 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;为加强对软件项目开发工作管理，缩短开发周期，提高软件开发质量，降低开发成本，提高定开发效率和效益，特制定软件开发流程管理制度。&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;第一章、总则&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;为保证日常工作正常有序的进行，让开发中各个环境更紧凑，更可控，需要尽可能实现项目管理的正规化，工作过程的流程化，以便提高软件质量，按期交付。&lt;/p&gt;
&lt;p&gt;1、软件开发总体遵循项目管理和软件工程的基本原则。&lt;/p&gt;
&lt;p&gt;2、项目管理涉及项目立项、项目计划和监控、配置管理。&lt;/p&gt;
&lt;p&gt;3、软件工程涉及需求分析、系统设计、软件实现、系统测试、用户测试、试运行、系统验收、系统上线和数据迁移、产品维护。&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;第二章、阶段成果&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;根据软件工程的过程，制定以下工作流程，并规定了各个重要环节需要提交的交付物。各阶段需提交的文档：&lt;/p&gt;
&lt;p&gt;1、立项：项目申请表，软件需求报告或设计方案。&lt;/p&gt;
&lt;p&gt;2、需求分析：项目研发主计划、需求规格说明书&lt;/p&gt;
&lt;p&gt;3、总体设计：概要设计说明书或功能模块描述&lt;/p&gt;
&lt;p&gt;4、详细设计：详细设计说明书，包括软件接口说明、单元测试计划。&lt;/p&gt;
&lt;p&gt;5、软件实现：软件功能说明、源代码说明或者注释&lt;/p&gt;
&lt;p&gt;6、产品测试：测试、测评报告&lt;/p&gt;
&lt;p&gt;7、产品发布：产品说明书、使用手册&lt;/p&gt;
&lt;p&gt;8、产品维护：问题反馈记录&lt;/p&gt;
&lt;p&gt;9、项目总结：提交客户方的项目总结和公司项目汇报的PPT。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;软件过程成果表：&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;阶段&lt;/th&gt;
&lt;th&gt;形成文档&lt;/th&gt;
&lt;th&gt;职责及文档成果描述&lt;/th&gt;
&lt;th&gt;负责人&lt;/th&gt;
&lt;th&gt;涉及范围&lt;/th&gt;
&lt;th&gt;备注&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;需求阶段&lt;/td&gt;
&lt;td&gt;项目立项报告(Word)&lt;/td&gt;
&lt;td&gt;明确甲乙双方责任及义务，需求方签字确认&lt;/td&gt;
&lt;td&gt;项目经理&lt;/td&gt;
&lt;td&gt;验收报告&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;业务需求说明书(Word)&lt;/td&gt;
&lt;td&gt;需求定义，阐述业务范围及内容，开发组负责制定最优技术设计方案&lt;/td&gt;
&lt;td&gt;项目经理/分析员&lt;/td&gt;
&lt;td&gt;验收报告&lt;/td&gt;
&lt;td&gt;大部分业务建模和需求，少部分分析设计&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;项目开发计划(Project)&lt;/td&gt;
&lt;td&gt;用户、领导、项目组都了解项目进度&lt;/td&gt;
&lt;td&gt;项目经理&lt;/td&gt;
&lt;td&gt;验收报告&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;设计阶段&lt;/td&gt;
&lt;td&gt;业务流程图体系设计书、详细设计说明书(Word/Visio)&lt;/td&gt;
&lt;td&gt;项目组成员分配任务，并召开讨论会议，讨论项目的技术架构和可能存在的技术难点，梳理业务流程，统一开发规则和风格等&lt;/td&gt;
&lt;td&gt;项目经理/分析员&lt;/td&gt;
&lt;td&gt;验收报告&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;数据库关系设计图、流程图(PowerDesigner)&lt;/td&gt;
&lt;td&gt;便于项目开发&lt;/td&gt;
&lt;td&gt;分析员&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;大部分分析设计，部分实施编程及测试，开始考虑部署&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;任务分配文档(Word)&lt;/td&gt;
&lt;td&gt;明确每个组员的开发任务及职责&lt;/td&gt;
&lt;td&gt;项目经理&lt;/td&gt;
&lt;td&gt;过程报告&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;问题说明报告(Word)&lt;/td&gt;
&lt;td&gt;让用户、领导及组员及时了解和发现问题&lt;/td&gt;
&lt;td&gt;项目经理&lt;/td&gt;
&lt;td&gt;过程报告&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;业务变更文档(Word)&lt;/td&gt;
&lt;td&gt;记录开发过程中用户提出的业务需求变更情况&lt;/td&gt;
&lt;td&gt;分析员&lt;/td&gt;
&lt;td&gt;过程报告&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;测试阶段&lt;/td&gt;
&lt;td&gt;项目测试方案及报告(Word)&lt;/td&gt;
&lt;td&gt;记录项目测试的方法、验证系统功能与性能的记录&lt;/td&gt;
&lt;td&gt;测试员&lt;/td&gt;
&lt;td&gt;验收报告&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;用户使用手册(Word)&lt;/td&gt;
&lt;td&gt;方便用户使用软件而提供的使用说明书&lt;/td&gt;
&lt;td&gt;测试员&lt;/td&gt;
&lt;td&gt;验收报告&lt;/td&gt;
&lt;td&gt;反复测试直至系统稳定&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;系统切换报告&lt;/td&gt;
&lt;td&gt;系统部署后的操作记录&lt;/td&gt;
&lt;td&gt;项目经理&lt;/td&gt;
&lt;td&gt;过程报告&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;用户培训报告&lt;/td&gt;
&lt;td&gt;用户培训文档&lt;/td&gt;
&lt;td&gt;项目经理&lt;/td&gt;
&lt;td&gt;过程报告&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;上线及运行&lt;/td&gt;
&lt;td&gt;项目验收报告(Word)&lt;/td&gt;
&lt;td&gt;记录甲乙双方签订项目验收报告&lt;/td&gt;
&lt;td&gt;项目经理&lt;/td&gt;
&lt;td&gt;验收报告&lt;/td&gt;
&lt;td&gt;部署及维护&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;项目总结性报告&lt;/td&gt;
&lt;td&gt;项目组通过此项目总结经验及不足&lt;/td&gt;
&lt;td&gt;项目经理&lt;/td&gt;
&lt;td&gt;总结报告&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;第三章、岗位设置&lt;/strong&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;岗位&lt;/th&gt;
&lt;th&gt;工作内容&lt;/th&gt;
&lt;th&gt;责任&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;项目经理&lt;/td&gt;
&lt;td&gt;1. 选定项目组成员，成立项目组，安排任务分工&amp;lt;br&amp;gt;2. 与客户进行沟通和协调(业务需求或非业务需求方面)，以及需求调研工作。&amp;lt;br&amp;gt;3. 制定开发主计划，包括需求、设计、编码、测试这几个阶段的计划。&amp;lt;br&amp;gt;4. 估计项目工作量&amp;lt;br&amp;gt;5. 制定小组开发进度表，对组内人员工作进度监控。&amp;lt;br&amp;gt;6. 和客户进行沟通，进行需求调研，记录需求分析文档，开编写系统总体设计方案&amp;lt;br&amp;gt;7. 对文档的质量进行检查。把关&amp;lt;br&amp;gt;8. 对组内成员的工作进行指导&lt;/td&gt;
&lt;td&gt;1. 对客户的沟通协调工作负责；&amp;lt;br&amp;gt;2. 对软件的开发效率、质量、费用负责&amp;lt;br&amp;gt;3. 对用户的需求分析的质量负责；&amp;lt;br&amp;gt;4. 对系统总体设计、详细设计文档质量负责&amp;lt;br&amp;gt;5. 制定小组开发进度表，对组内人员工作进度监控。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;软件设计师&lt;/td&gt;
&lt;td&gt;1. 负责系统的模块设计，详细设计文档&amp;lt;br&amp;gt;2. 给制界面原型demo等，设计功能使用的具体描述、行为者、前置条件、后置条件、UI描述、业务流程/子流程/分支流程，界面说明等。完成大部分的前端设计，小部分的后端设计。&amp;lt;br&amp;gt;3. 负责技术难度大的模块的代码或者公用模块代码的编写、维护&amp;lt;br&amp;gt;4. 对自己负责模块的详细设计、代码编写。&amp;lt;br&amp;gt;5. 对小组内人员进行技术指导&lt;/td&gt;
&lt;td&gt;1. 对组内人员的开发效率负责；&amp;lt;br&amp;gt;2. 对产品整体风格负责；&amp;lt;br&amp;gt;3. 对项目整体设计流程负责；&amp;lt;br&amp;gt;4. 对自己模块的开发效率和质量负责。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;程序员&lt;/td&gt;
&lt;td&gt;1. 与项目经理沟通确认某个模块的需求和实现方法&amp;lt;br&amp;gt;2. 负责某个模块的代码编写、维护&amp;lt;br&amp;gt;3. 对其他模块的代码的维护&amp;lt;br&amp;gt;4. 负责与测试人员的交互，处理测试人员反馈的问题&lt;/td&gt;
&lt;td&gt;1. 对自己模块的开发效率和质量负责。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;测试工程师&lt;/td&gt;
&lt;td&gt;1. 根据用户需求分析和系统总体设计，编写测试文档和测试用例。&amp;lt;br&amp;gt;2. 对系统的功能、性能、异常进行测试。&amp;lt;br&amp;gt;3. 编写测试文档和操作指导手册。&lt;/td&gt;
&lt;td&gt;1. 对测试的质量负责&amp;lt;br&amp;gt;2. 对测试文档和操作手册的质量负责。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;根据公司目前的开发过程主要分为分析、开发、测试三个阶段。分析阶段完成用户需求文档的编写，系统总体设计的编写；开发阶段完成设计文档的编写，代码的编写、代码的维护。测试阶段完成系统的测试，测试文档及其他材料。通过逐渐的调整岗位，明确工作职责，逐步实现项目经理，软件设计师，程序员，测试工程师的岗位设置。&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;第四章、项目立项&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;1、分析人员进行应用调查与分析，确认软件的应用需求。&lt;/p&gt;
&lt;p&gt;2、成立项目评审会，开发总监、部门经理和指定人员必须参加。对项目进行可行性研究，编写项目建议书，评估项目的难度和工作量，形成可行性研究报告。&lt;/p&gt;
&lt;p&gt;3、根据项目配置的优劣成立项目开发组，制定软件开发计划，确定项目经理，由部门和项目经理共同来确定具体项目配置，知识技能要求，团队成员及团队的角色。&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;第五章、项目计划与监控&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;1、以项目为单位，项目经理负责整个项目的计划、组织和控制。&lt;/p&gt;
&lt;p&gt;2、在整个项目过程中，项目经理定期检查项目进度和完成情况，调整人员分工和安排。&lt;/p&gt;
&lt;p&gt;3、项目计划需要变更时，需要明确变更内容并及时汇报。项目经理需要说明客户变更原因并将变更说明提交公司领导审核，以便根据变更内容及时调整计划。。&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;第六章、需求分析&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;1、对用户提出的需求进行分析汇总，梳理用户的业务流程和详细的功能定义。&lt;/p&gt;
&lt;p&gt;2、做出简单的界面原型，与客户进行有效的沟通， 编写需求详细说明书。&lt;/p&gt;
&lt;p&gt;3、根据现有条件进行估计，制定项目进度，制定详细的软件开发计划。&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;第七章、总体设计&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;1、在该阶段确定总体结构和软件开发架构，文件命名规范，编码规范。可按软件需求划分成子系统，也可直接定义目标系统的功能模块及各个功能模块的关系。&lt;/p&gt;
&lt;p&gt;3、确定软件模块结构，给出每个功能模块的功能描述、数据接口描述，并完成系统概要设计说明书。&lt;/p&gt;
&lt;p&gt;4、完成数据库的设计，并编写数据库设计说明书。&lt;/p&gt;
&lt;p&gt;5、完成的文档需提交公司进行归档管理。&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;第八章、详细设计&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;1、调整前一步设计的不足，确认各模块之间的详细接口信息。&lt;/p&gt;
&lt;p&gt;2、设计功能使用的具体描述、行为者、前置条件、后置条件、UI描述、业务流程/子流程/分支流程，界面说明等。&lt;/p&gt;
&lt;p&gt;3、确定模块内的数据流或控制流，对每个程序模块必须确定所有输入、输出和处理功能。&lt;/p&gt;
&lt;p&gt;4、汇总并提交所有相关文档，审核确认质量和进度。&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;第九章、软件实现&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;1、项目组根据概要设计说明书、详细设计说明书制定系统实现计划&lt;/p&gt;
&lt;p&gt;2、有条件的情况下保证开发、测试和生产环境独立。选择软件工具，明确项目成员的职责分工，按照编码规范和详细设计实现软件功能。&lt;/p&gt;
&lt;p&gt;3、代码应满足结构良好，清晰易读，且与设计一致，符合编码规范。&lt;/p&gt;
&lt;p&gt;4、开发人员需要软件实现过程中编写软件功能说明，源代码说明。软件功能说明文档应说明项目名称、编号、软件名称和版本号，软件功能、主要功能实现过程。源代码说明应说明项目编号、软件名称、功能，全局变量、数据库字典、函数功能、接口。该文档包含在源代码文件中，以注释形式存在。&lt;/p&gt;
&lt;p&gt;5、项目组进行单元测试和集成测试。开发人员处理测试人员反馈的测试问题，并以书面形式反馈主要问题及解决办法，直至系统运行稳定。&lt;/p&gt;
&lt;p&gt;6、汇总并提交所有相关文档，提交公司备案。&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;第十章、软件测试&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;1、根据单据测试和集成测试两个过程，制定测试计划。按阶段设计测试实例，并将测试结果记录，未通过的的反馈给开发人员调整。&lt;/p&gt;
&lt;p&gt;2、完成测试文档、操作手册、安装维护手册的编写。&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;第十一章、用户培训&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;1、准备用户培训计划、培训手册&lt;/p&gt;
&lt;p&gt;2、确定培训时间、培训地点，向用户进行系统使用培训、操作指导及提供软件操作手册。&lt;/p&gt;
&lt;p&gt;3、保留培训签到表，用户意见等存档。&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;第十二章、系统上线&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;1、 制定上线计划，确定上线工作时间表，部署的环境。&lt;/p&gt;
&lt;p&gt;2、上线操作步骤以及问题处理步骤；&lt;/p&gt;
&lt;p&gt;3、根据软件特点、客户需求进行软件部署，并记录软件部署和运行结果；&lt;/p&gt;
&lt;p&gt;4、项目组根据系统运行请款对系统进行优化，记录系统的运行情况、系统问题和处理后的版本。&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;第十三章、系统验收&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;1、验收工作准备，按要求整理项目成果物，打印装订成册，并提交客户方。&lt;/p&gt;
&lt;p&gt;2、系统主要使用部门及信息技术部门联合成立项目验收小组，从需求功能及技术需求层面对系统进行综合评估和项目成果物的审核，根据验收情况形成系统验收报告&lt;/p&gt;
&lt;p&gt;3、应用部门及信息技术部门负责人根据系统试运行情况签署验收意见。&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;第十四章、产品维护&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;1、调出项目主要开发人员，按照合同要求安排维护人员对系统进行技术支持。&lt;/p&gt;
&lt;p&gt;2、系统需求变更或调整，记录变更原因和软件及源代码的版本控制，按照软件变更要求对系统进行维护。&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;第章十五、源码和文档&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;1、源代码/文档管理采用版本控制软件SVN。&lt;/p&gt;
&lt;p&gt;2、按项目的阶段性完成源代码、文档的上传。项目负责人每天对代码进行检查，开发总监或部门经理定期进行抽查。&lt;/p&gt;
&lt;p&gt;3、文档分为项目文档和个人文档，文档上传前进行归类和汇总。&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;第十六章、质量检查&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;1、项目负责人每天要检查成员的工作完成情况，特别是新员工的工作进展；&lt;/p&gt;
&lt;p&gt;2、工作抽查制度：不定期的进行抽检，并将检查对象、检查时间、检查内容、检查结果反馈给被抽检人。&lt;/p&gt;
&lt;p&gt;3、内部审核制度：针对业务需求、概要设计(功能界面、数据库)或疑难问题组织评审会，提出意见或解决方案。&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;第十七章、文档规范&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;1、需按照软件实施的阶段落实成果物，参照《软件过程提交成果表》。&lt;/p&gt;
&lt;p&gt;2、如果客户有特殊要求，请按照客户要求的规范完成。并将最终的问题提交公司归档备份。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;阶段&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;提交成果&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;详细内容&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;立项&lt;/td&gt;
&lt;td&gt;项目申请表&lt;/td&gt;
&lt;td&gt;项目名称、编号及简要描述；申请部门、申请人及联系方式；项目背景和目标阐述；预期效益分析；初步时间进度安排。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;软件需求报告或设计方案&lt;/td&gt;
&lt;td&gt;业务需求概述（涉及业务流程和关键业务点）；用户角色分析及需求描述；功能需求清单；非功能需求；初步技术选型和架构设想。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;需求分析&lt;/td&gt;
&lt;td&gt;项目研发主计划&lt;/td&gt;
&lt;td&gt;项目整体时间表（明确阶段起止时间）；里程碑设定及交付成果；项目资源分配；风险评估及应对措施。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;需求规格说明书&lt;/td&gt;
&lt;td&gt;详细业务流程描述（流程图和文字说明）；功能需求详细定义（输入、输出、处理逻辑等）；界面原型设计；数据需求分析；性能需求指标及测试方法。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;总体设计&lt;/td&gt;
&lt;td&gt;概要设计说明书或功能模块描述&lt;/td&gt;
&lt;td&gt;系统架构设计（软件层次结构、模块划分及相互关系）；功能模块概述；接口设计；数据结构设计；技术选型说明。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;数据库设计说明书&lt;/td&gt;
&lt;td&gt;数据库概念模型设计（ER 图）；数据库逻辑结构设计（表结构、字段类型、约束条件等）；数据库物理结构设计（存储方式、索引设计等）；数据备份和恢复策略。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;详细设计&lt;/td&gt;
&lt;td&gt;详细设计说明书&lt;/td&gt;
&lt;td&gt;每个功能模块详细设计（算法、流程控制、数据处理等）；界面设计细节；接口实现细节；错误处理机制设计；单元测试计划。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;软件接口说明&lt;/td&gt;
&lt;td&gt;外部接口说明（与其他系统接口协议、数据格式等）；内部模块间接口说明（调用方式、参数传递等）；接口测试计划和方法。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;软件实现&lt;/td&gt;
&lt;td&gt;软件功能说明&lt;/td&gt;
&lt;td&gt;项目名称、编号、软件名称和版本号；软件功能概述；主要功能实现过程；软件运行环境要求。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;源代码说明&lt;/td&gt;
&lt;td&gt;项目编号、软件名称、功能描述；全局变量说明；数据库字典说明；函数功能说明；接口说明。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;单元测试和集成测试报告&lt;/td&gt;
&lt;td&gt;测试环境描述；测试用例执行情况；问题及缺陷记录；问题解决情况。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;产品测试&lt;/td&gt;
&lt;td&gt;测试报告&lt;/td&gt;
&lt;td&gt;测试范围和目标；测试方法和策略；测试结果分析；系统质量评估。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;测试文档&lt;/td&gt;
&lt;td&gt;详细测试用例文档；测试过程记录文档；测试环境配置文档。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;操作手册&lt;/td&gt;
&lt;td&gt;系统概述；安装和配置说明；操作指南；常见问题解答。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;安装维护手册&lt;/td&gt;
&lt;td&gt;系统安装步骤；系统维护方法；系统升级方法。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;用户培训&lt;/td&gt;
&lt;td&gt;用户培训计划&lt;/td&gt;
&lt;td&gt;培训目标和对象；培训内容和课程安排；培训方式和方法；培训考核方式。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;培训手册&lt;/td&gt;
&lt;td&gt;侧重于培训内容，可包括案例分析、实际操作指导等。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;培训签到表&lt;/td&gt;
&lt;td&gt;记录参加培训人员名单和签到情况。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;用户意见&lt;/td&gt;
&lt;td&gt;收集用户在培训过程中的意见和建议。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;系统上线&lt;/td&gt;
&lt;td&gt;上线计划&lt;/td&gt;
&lt;td&gt;上线时间表；上线准备工作；上线步骤和流程；风险评估及应对措施。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;上线操作步骤及问题处理步骤&lt;/td&gt;
&lt;td&gt;详细上线操作指南；问题处理流程；回退方案。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;软件部署记录和运行结果&lt;/td&gt;
&lt;td&gt;记录软件部署过程和结果；系统运行结果记录。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;系统验收&lt;/td&gt;
&lt;td&gt;项目成果物（整理装订成册）&lt;/td&gt;
&lt;td&gt;需求规格说明书、设计文档、测试文档、操作手册、安装维护手册等所有项目相关文档整理装订。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;系统验收报告&lt;/td&gt;
&lt;td&gt;验收背景和目的；验收依据；验收内容和方法；验收结果分析；验收结论。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;产品维护&lt;/td&gt;
&lt;td&gt;问题反馈记录&lt;/td&gt;
&lt;td&gt;记录用户反馈问题和意见；问题处理情况；问题跟踪记录。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;变更原因及软件和源代码版本控制记录&lt;/td&gt;
&lt;td&gt;记录系统变更原因和需求来源；软件和源代码版本控制记录。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;项目总结&lt;/td&gt;
&lt;td&gt;提交客户方的项目总结&lt;/td&gt;
&lt;td&gt;项目概述；项目成果总结；项目经验教训；对客户的建议。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;公司项目汇报 PPT&lt;/td&gt;
&lt;td&gt;以 PPT 形式向公司汇报项目情况，包括背景、目标、过程、成果、经验教训等。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;第十八章、软件变更&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;为规范软件变更与维护管理，特制定本制度。&lt;/p&gt;
&lt;p&gt;(本制度适用于应用系统开发完毕并正式上线，移交给客户方之后的运行支持及系统变更工作。)&lt;/p&gt;
&lt;p&gt;1、系统变更工作可分为功能完善维护、系统缺陷修改、统计报表生成。&lt;/p&gt;
&lt;p&gt;2、需求部门提出系统变更需求，开发部技术支持人员根据重要性和紧迫性做判断，确定其优先级和影响程度，并进行相应处理，同时将变更需求整理成系统变更申请表。&lt;/p&gt;
&lt;p&gt;3、系统变更实现过程按照软件开发过程规定进行，遵循软件开发过程统一的编码标准和版本控制，并经过测试通过才能完成部署和上线。&lt;/p&gt;
&lt;p&gt;4、在系统变更完成后，开发人员需将系统变更表的执行结果找业务部门负责人签字后，提交至公司进行归档管理。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>RPA工具使用介绍</title><link>https://blog.ithuo.net/posts/what-is-rpa/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/what-is-rpa/</guid><pubDate>Sat, 29 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;RPA 是什么？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;RPA 的全称是 &lt;strong&gt;机器人流程自动化（Robotic Process Automation）&lt;/strong&gt;，机器人流程自动化（RPA）是一种软件技术，可轻松创建、部署和管理软件机器人，模拟人类行为，与数字系统和软件进行互动。软件机器人可像人类一样工作，比如理解屏幕上的内容、正确完成按键、系统导航、识别和提取数据，以及完成一系列的既定行为。但软件机器人工作速度比人类更快，更稳定，且无需站起来舒筋展骨或喝咖啡休息。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;RPA 机器人能做什么？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;遵循一套预定义的指令，就像人一样与软件应用程序互动，包括点击按钮、填写表格、复制粘贴数据、移动文件等。&lt;/li&gt;
&lt;li&gt;机器人可以 24/7 不间断工作，远超出人类的工作效率。&lt;/li&gt;
&lt;li&gt;它们非常准确，不像人类容易犯错。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;使用 RPA 的好处有哪些？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;提高效率:&lt;/strong&gt; RPA 可以自动执行耗时又乏味的任务，让员工专注于更具战略性的工作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;提升准确性:&lt;/strong&gt; 机器人比人类更不容易出错，可减少错误发生，提高质量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;降低成本:&lt;/strong&gt; RPA 可以帮助企业减少人力成本，实现节省。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;提高客户满意度:&lt;/strong&gt; 自动化一些对客户造成困扰的任务，可以提升客户满意度。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;RPA 的一些应用示例：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;数据录入:&lt;/strong&gt; 机器人可以自动将客户信息录入 CRM 系统等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;客户服务:&lt;/strong&gt; 机器人可以回答客户问题，解决简单问题。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;财务报告:&lt;/strong&gt; 机器人可以自动生成财务报告。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;订单处理:&lt;/strong&gt; 机器人可以自动处理订单。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;RPA 是否适合您的企业？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;RPA 可以有效提升效率、准确性和客户满意度。然而，您需要慎重考虑 RPA 是否适合您的企业。需要考虑的因素包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;工作性质:&lt;/strong&gt; RPA 最适合重复、规则化的任务。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实施成本:&lt;/strong&gt; RPA 软件可能价格不菲，所以需要确保您能获得投资回报。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对员工的影响:&lt;/strong&gt; RPA 可能替代一些岗位，所以需要考虑对员工的影响。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果您想尝试使用 RPA，建议先选择一个小型的试点项目，看看它在您的业务中是否奏效。&lt;/p&gt;
&lt;h3&gt;国外三大RPA厂商&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;UiPath:&lt;/strong&gt; &lt;a href=&quot;https://www.uipath.com/&quot;&gt;https://www.uipath.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blue Prism:&lt;/strong&gt; &lt;a href=&quot;https://www.blueprism.com/&quot;&gt;https://www.blueprism.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automation Anywhere:&lt;/strong&gt; &lt;a href=&quot;https://www.automationanywhere.com/&quot;&gt;https://www.automationanywhere.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;影刀RPA&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ydrpa.yuque.com/org-wiki-ydrpa-xtutvv/ggc4i2/rua5tg3s8t33zn25&quot;&gt;Amazon亚马逊商品评论采集机器人 (yuque.com)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Puppeteer&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developers.cloudflare.com/browser-rendering/platform/puppeteer/&quot;&gt;Puppeteer · Browser Rendering docs (cloudflare.com)&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Foundry 新手指南：在 W3Q 网络上开发、测试和部署智能合约</title><link>https://blog.ithuo.net/posts/foundry-beginners-guide-developing-testing-and-deploying-smart-contracts-on-w3q-network/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/foundry-beginners-guide-developing-testing-and-deploying-smart-contracts-on-w3q-network/</guid><pubDate>Sun, 23 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;1. 引言&lt;/h2&gt;
&lt;p&gt;随着区块链技术的不断发展,智能合约开发已成为Web3世界的重要组成部分。本文将指导您如何使用Foundry工具套件在W3Q网络上开发、测试、部署和与智能合约交互。无论您是刚接触智能合约开发的新手,还是寻求提升效率的经验开发者,本文都将为您提供有价值的见解和实用技巧。&lt;/p&gt;
&lt;h2&gt;2. W3Q网络简介&lt;/h2&gt;
&lt;p&gt;W3Q是一个专注于简化Web3开发的区块链平台。它提供了以下特性:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;兼容EVM的智能合约执行环境&lt;/li&gt;
&lt;li&gt;低gas费用&lt;/li&gt;
&lt;li&gt;快速交易确认&lt;/li&gt;
&lt;li&gt;开发者友好的工具和文档&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;W3Q的Galileo测试网络信息:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;网络ID: 3334&lt;/li&gt;
&lt;li&gt;RPC URL: &lt;a href=&quot;https://galileo.web3q.io:8545/&quot;&gt;https://galileo.web3q.io:8545&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;区块浏览器: &lt;a href=&quot;https://explorer.galileo.web3q.io/&quot;&gt;https://explorer.galileo.web3q.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;原生代币: W3Q&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3. Foundry简介&lt;/h2&gt;
&lt;p&gt;Foundry是一套用Rust编写的快速、可移植和模块化的以太坊开发工具。它主要包含以下组件:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Forge: 用于测试、构建和部署智能合约&lt;/li&gt;
&lt;li&gt;Cast: 用于与智能合约交互的命令行工具&lt;/li&gt;
&lt;li&gt;Anvil: 本地以太坊节点,用于测试和开发&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4. 安装Foundry&lt;/h2&gt;
&lt;p&gt;首先,让我们安装Foundry:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -L &amp;lt;https://foundry.paradigm.xyz&amp;gt; | bash foundryup
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5. 创建项目&lt;/h2&gt;
&lt;p&gt;创建一个新的Foundry项目:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;forge init my_project
cd my_project
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;6. 编写智能合约&lt;/h2&gt;
&lt;p&gt;让我们创建一个简单的公共留言板合约。在&lt;code&gt;src&lt;/code&gt;目录下创建&lt;code&gt;PublicMessageBoard.sol&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

contract PublicMessageBoard {
    struct Message {
        address sender;
        string content;
        uint256 timestamp;
    }

    Message[] public messages;

    event NewMessage(address indexed sender, string content, uint256 timestamp);

    function postMessage(string memory _content) public {
        require(bytes(_content).length &amp;gt; 0, &quot;Message cannot be empty&quot;);
        require(bytes(_content).length &amp;lt;= 280, &quot;Message too long&quot;);

        messages.push(Message({
            sender: msg.sender,
            content: _content,
            timestamp: block.timestamp
        }));

        emit NewMessage(msg.sender, _content, block.timestamp);
    }

    function getAllMessages() public view returns (Message[] memory) {
        return messages;
    }

    function getMessageCount() public view returns (uint256) {
        return messages.length;
    }

    function getMessage(uint256 index) public view returns (address, string memory, uint256) {
        require(index &amp;lt; messages.length, &quot;Message index out of bounds&quot;);
        Message memory message = messages[index];
        return (message.sender, message.content, message.timestamp);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;7. 测试合约&lt;/h2&gt;
&lt;p&gt;在&lt;code&gt;test&lt;/code&gt;目录下创建&lt;code&gt;PublicMessageBoard.t.sol&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import &quot;forge-std/Test.sol&quot;;
import &quot;../src/PublicMessageBoard.sol&quot;;

contract PublicMessageBoardTest is Test {
    PublicMessageBoard public board;

    function setUp() public {
        board = new PublicMessageBoard();
    }

    function testPostMessage() public {
        board.postMessage(&quot;Hello, World!&quot;);
        assertEq(board.getMessageCount(), 1);

        (address sender, string memory content, ) = board.getMessage(0);
        assertEq(sender, address(this));
        assertEq(content, &quot;Hello, World!&quot;);
    }

    function testEmptyMessage() public {
        vm.expectRevert(&quot;Message cannot be empty&quot;);
        board.postMessage(&quot;&quot;);
    }

    function testLongMessage() public {
        string memory longMessage = new string(281);
        vm.expectRevert(&quot;Message too long&quot;);
        board.postMessage(longMessage);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行测试:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;forge test
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;8. 部署合约&lt;/h2&gt;
&lt;p&gt;创建一个部署脚本&lt;code&gt;script/DeployMessageBoard.s.sol&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import &quot;forge-std/Script.sol&quot;;
import &quot;../src/PublicMessageBoard.sol&quot;;

contract DeployMessageBoard is Script {
    function run() external {
        uint256 deployerPrivateKey = vm.envUint(&quot;PRIVATE_KEY&quot;);
        vm.startBroadcast(deployerPrivateKey);

        PublicMessageBoard messageBoard = new PublicMessageBoard();
        console.log(&quot;PublicMessageBoard deployed at:&quot;, address(messageBoard));

        vm.stopBroadcast();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;创建&lt;code&gt;.env&lt;/code&gt;文件并添加以下内容:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PRIVATE_KEY=your_private_key_here
W3Q_RPC_URL=https://galileo.web3q.io:8545
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修改&lt;code&gt;foundry.toml&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[profile.default]
src = &quot;src&quot;
out = &quot;out&quot;
libs = [&quot;lib&quot;]

[rpc_endpoints]
w3q_galileo = &quot;${W3Q_RPC_URL}&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;部署合约:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;source .env
forge script script/DeployMessageBoard.s.sol:DeployMessageBoard --rpc-url $W3Q_RPC_URL --broadcast --legacy --chain-id 3334 -vvvv
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;9. 验证合约&lt;/h2&gt;
&lt;p&gt;目前,W3Q网络可能不支持自动合约验证。您可能需要手动在区块浏览器上验证合约。&lt;/p&gt;
&lt;h2&gt;10. 与合约交互&lt;/h2&gt;
&lt;p&gt;使用Cast与合约交互:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 发布消息
cast send $CONTRACT_ADDRESS &quot;postMessage(string)&quot; &quot;Hello, W3Q!&quot; --rpc-url $W3Q_RPC_URL --private-key $PRIVATE_KEY --gas-price 10000000000 --chain-id 3334

# 获取消息数量
cast call $CONTRACT_ADDRESS &quot;getMessageCount()&quot; --rpc-url $W3Q_RPC_URL

# 获取特定消息
cast call $CONTRACT_ADDRESS &quot;getMessage(uint256)&quot; 0 --rpc-url $W3Q_RPC_URL
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;11. 常见问题和解决方案&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Gas价格问题:
如果交易卡住,可能是因为gas价格设置过低。使用以下命令查询当前gas价格:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cast gas-price --rpc-url $W3Q_RPC_URL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后相应调整gas价格。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Nonce问题:
确保使用正确的nonce。查询当前nonce:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cast nonce $WALLET_ADDRESS --rpc-url $W3Q_RPC_URL
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;余额不足:
确保账户有足够的W3Q代币支付gas费用:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cast balance $WALLET_ADDRESS --rpc-url $W3Q_RPC_URL
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;交易卡住:
如果交易长时间未被确认,可以尝试用相同的nonce发送一个新交易,但提高gas价格:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cast send $CONTRACT_ADDRESS &quot;postMessage(string)&quot; &quot;New message&quot; --rpc-url $W3Q_RPC_URL --private-key $PRIVATE_KEY --gas-price 15000000000 --nonce &amp;lt;stuck_transaction_nonce&amp;gt; --chain-id 3334
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;RPC节点响应慢:
排查上面几个步骤，不行就加gas&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;合约调用失败:
使用&lt;code&gt;cast estimate&lt;/code&gt;估算所需的gas:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cast estimate $CONTRACT_ADDRESS &quot;postMessage(string)&quot; &quot;Hello, W3Q!&quot; --rpc-url $W3Q_RPC_URL --from $WALLET_ADDRESS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后在发送交易时使用&lt;code&gt;--gas-limit&lt;/code&gt;参数指定足够的gas。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;12. 结论&lt;/h2&gt;
&lt;p&gt;使用Foundry在W3Q网络上开发和部署智能合约是一个强大而灵活的过程。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Mastering Go: A Comprehensive Tutorial</title><link>https://blog.ithuo.net/posts/how-to-learning-golang-use-comprehensive-tutorial/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/how-to-learning-golang-use-comprehensive-tutorial/</guid><pubDate>Sun, 02 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction to Golang&lt;/h2&gt;
&lt;p&gt;Go, also known as Golang, is a statically typed, strongly typed programming language that has become increasingly popular in recent years. Go was designed by Google engineers to be a simple, efficient, and scalable language that is well-suited for building modern, concurrent applications. In this comprehensive tutorial, we&apos;ll explore the key features and concepts of Go, from the basics of variables and data types to more advanced topics like concurrency and building APIs.&lt;/p&gt;
&lt;h2&gt;Constants, Variables, and Basic Data Types&lt;/h2&gt;
&lt;p&gt;One of the defining features of Go is its strict type system. In Go, you must explicitly declare the type of a variable when you create it, and that type cannot change later on without type conversion. Go also has a set of basic data types, including integers (int, int8, int16, int32, int64), floating-point numbers (float32, float64), and strings.&lt;/p&gt;
&lt;p&gt;Go is a strongly typed language, which means that the operations you can perform on a variable depend on its type. For example, you cannot add an integer and a string together in Go, unlike in a weakly typed language like JavaScript.&lt;/p&gt;
&lt;p&gt;Go also has a built-in compiler that translates your code into machine code, producing a standalone binary file that can be executed. This is in contrast to languages like Python, which use interpreters that translate the code line-by-line as it&apos;s running, adding overhead and making the execution slower.&lt;/p&gt;
&lt;h2&gt;Functions and Control Structures&lt;/h2&gt;
&lt;p&gt;In Go, you define a function using the `func\&lt;code&gt; keyword, followed by the function name and its parameters. Functions can return one or more values, and Go has a variety of control structures, including \&lt;/code&gt;if-else\&lt;code&gt; statements, \&lt;/code&gt;switch\&lt;code&gt; statements, and \&lt;/code&gt;for\` loops.&lt;/p&gt;
&lt;p&gt;Go also has a unique way of handling errors, where functions can return an error value in addition to their regular return values. This allows you to easily check for and handle errors in your code.&lt;/p&gt;
&lt;h2&gt;Arrays, Slices, Maps, and Loops&lt;/h2&gt;
&lt;p&gt;Go has several built-in data structures, including arrays, slices, and maps. Arrays in Go have a fixed length, while slices are more flexible and can grow or shrink in size. Maps are key-value data structures that allow you to quickly look up and access data.&lt;/p&gt;
&lt;p&gt;Looping in Go is done using the `for\&lt;code&gt; keyword, and you can use a variety of loop structures, including the traditional \&lt;/code&gt;for\&lt;code&gt; loop, the \&lt;/code&gt;for-range\&lt;code&gt; loop for iterating over arrays and slices, and the \&lt;/code&gt;for\` loop with no condition for creating infinite loops.&lt;/p&gt;
&lt;h2&gt;Strings, Runes, and Bytes&lt;/h2&gt;
&lt;p&gt;Strings in Go are represented as arrays of bytes, using the UTF-8 encoding. This means that characters outside the basic ASCII character set may take up more than one byte in a string. Go also has a special data type called a `rune\`, which represents a single Unicode character.&lt;/p&gt;
&lt;p&gt;Working with strings in Go can be a bit more complex than in some other languages, but understanding the underlying byte-based representation and the `rune\` data type can help you write more robust and efficient string-handling code.&lt;/p&gt;
&lt;h2&gt;Structs and Interfaces&lt;/h2&gt;
&lt;p&gt;Go&apos;s structs are user-defined data types that allow you to group related data together. Structs can have fields of different types, and you can define methods that operate on struct instances.&lt;/p&gt;
&lt;p&gt;Interfaces in Go are a way to define a set of method signatures that a type must implement in order to be considered an implementation of that interface. Interfaces allow you to write code that is more generic and flexible, as it can work with any type that implements the required methods.&lt;/p&gt;
&lt;h2&gt;Pointers&lt;/h2&gt;
&lt;p&gt;Pointers in Go are a way to work with the memory addresses of variables, rather than just their values. Pointers can be useful for passing large data structures to functions without creating copies, and for modifying the contents of variables from within a function.&lt;/p&gt;
&lt;p&gt;Pointers can be a bit tricky to work with, especially when it comes to things like null pointers and pointer arithmetic, but understanding them is an important part of becoming a proficient Go programmer.&lt;/p&gt;
&lt;h2&gt;Goroutines and Concurrency&lt;/h2&gt;
&lt;p&gt;One of Go&apos;s key features is its built-in support for concurrency, which allows you to run multiple tasks simultaneously. Go achieves this through the use of &quot;goroutines&quot;, which are lightweight threads of execution that can be spawned and managed easily.&lt;/p&gt;
&lt;p&gt;Go also provides a powerful set of concurrency primitives, including channels, which allow goroutines to communicate and share data safely. Channels can be used to pass data between goroutines, and they also provide a way to synchronize the execution of multiple goroutines.&lt;/p&gt;
&lt;h2&gt;Generics&lt;/h2&gt;
&lt;p&gt;Go 1.18 introduced support for generics, which allow you to write code that can work with a variety of data types, rather than being limited to a specific type. Generics can be particularly useful when working with data structures and algorithms that need to be able to handle different types of data.&lt;/p&gt;
&lt;p&gt;Generics in Go work by allowing you to define type parameters, which act as placeholders for the actual types that will be used when the code is executed. This allows you to write more reusable and flexible code, without sacrificing the type safety that Go is known for.&lt;/p&gt;
&lt;h2&gt;Building an API&lt;/h2&gt;
&lt;p&gt;In the final part of this tutorial, we&apos;ll put everything we&apos;ve learned together to build a simple RESTful API using Go. We&apos;ll cover topics like setting up the project structure, defining the API endpoints, implementing authentication and authorization, and interacting with a database.&lt;/p&gt;
&lt;p&gt;By the end of this section, you&apos;ll have a solid understanding of how to use Go to build modern, scalable, and secure web applications and APIs.&lt;/p&gt;
&lt;p&gt;So, let&apos;s get started on your journey to mastering Go! Remember to hit that like button and subscribe to the channel to stay up-to-date with the latest videos in this series.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>研发效能度量之常用分析方法</title><link>https://blog.ithuo.net/posts/how-to-measure-r-d-efficiency-analysis/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/how-to-measure-r-d-efficiency-analysis/</guid><pubDate>Tue, 16 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;正如 Douglas W. Hubbard 在他的畅销书《How to Measure Anything》中所指出的那样，“如果一种度量真的很重要，那是因为它必须对决策和行为产生一些可以想象的影响。”如果我们不能确定一个度量指标可否影响决策，以及如何改变这些决策，那么这种度量就没有价值。&lt;/p&gt;
&lt;p&gt;对于度量指标的分析，下面我们介绍一些常用的方法：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/a39fbd4694c272ed313afe6b93cdf80e.png&quot; alt=&quot;2023060541.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1 趋势分析&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;趋势比绝对值更能说明问题。&lt;/p&gt;
&lt;p&gt;在度量研发效能的指标时，随着时间推移的改善趋势会比绝对值更有意义。每个组织、每个部门、每个团队、每个人都有不同的起点和上下文背景，对度量指标的绝对值进行横向比较很可能有失偏颇。针对每个独立的个体来说，度量其随时间推移的变化趋势更能获取到有效的信息。&lt;/p&gt;
&lt;p&gt;举个例子，下图是在某个部门中推进研发效能分析时绘制出来的趋势图。可以看到，在 2019 年 7 月份之前，随着时间的推移，交付周期持续处于上升趋势，即交付需求越来越慢。在进行复盘时，当时的管理者识别到了这一问题，虽然大家工作看起来很繁忙（资源利用率很高），但从业务或客户的角度来看，研发效率的体验却在持续下降（流动效率降低）。于是，当时管理者就决定指派专人负责研发效能的诊断分析和提升工作，对交付周期问题直接进行干预，通过一系列改进措施扭转这个趋势。在图中红圈位置是一个转折点，交付周期在 2019 年 8 月之后有了明显下降，说明所采取的干预措施是有效果的，在度量的指导下发现并处理了问题，最终该部门效能得到了提升。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/b95686eb5e6f265b6769b28816c95458.png&quot; alt=&quot;2023060542.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;下图是另外一个趋势分析的案例。这个部门核心的关注点是线上质量，使用缺陷逃逸率指标来进行度量。可以看到从 2019 年 Q2 到 2020 年 Q3，缺陷逃逸率一直处于下行趋势。但更为重要的是，是采取了什么样的措施和实践才达成了这一目标呢？图中的代码评审覆盖率、单元测试数量和通过率的趋势图正是这一问题的答案。可以看到，因为在背后付出了很多质量内建活动的努力，才让线上缺陷逃逸减少的这一目标得以达成。我们通过趋势分析，看到了多个指标之间的关联性，这种关联性分析方法非常有用，我们将在后文中展开说明。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/bed8087ee70c3ede4bcb575ad2c49b30.png&quot; alt=&quot;2023060543.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2 下钻分析&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;下钻分析可以帮助我们从宏观到微观，从表象到根因逐层排查问题，找到影响效能的瓶颈点。常见的下钻分析包括按阶段下钻（针对交付周期类指标）、按聚合维度进行下钻、按在制品进行下钻等。下面我们来看一些例子。&lt;/p&gt;
&lt;p&gt;按阶段下钻&lt;/p&gt;
&lt;p&gt;我们经常看到的现象是，如果产研部门被业务部门抱怨说交付速度太慢，产研部门的管理者头脑中的第一反应很可能是：再多招聘一些开发人员吧！从约束理论的角度来看，交付管道中至少会存在一个约束因素，限制了全局流动效率的潜能。但这个约束具体是在哪个阶段，很可能与我们预想的完全不同。&lt;/p&gt;
&lt;p&gt;在下面这个案例中，部门碰到的问题就是交付周期较长。于是，把交付周期按照阶段下钻之后形成了一张柱形图。从图中可以看到，需求的平均开发周期在 5 天左右，其实并不算很长，但开发前有一个等待周期也接近 5 天，另外还有多个阶段的平均耗时接近甚至高于开发周期。比如测试阶段耗时超过 9 天，方案及 PRD 阶段耗时接近 6 天。在精益理论中，我们可以把活动分为三类：增值的活动（如写代码等）、非增值但必要的活动（如测试等）、浪费（如等待、缺陷导致的返工）。我们要最大化增值的活动，优化非增值但必要的活动，消除不必要的浪费。那么在这个案例中，我们就找到了改进的大致方向，再结合其他指标进一步进行问题排查，应该就可以得出有针对性的优化策略了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/371bd7674a4af30b7ffbc43243ad9a75.png&quot; alt=&quot;2023060544.png&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;按聚合维度下钻&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;研发效能度量平台在采集到各研发工具产出的效能数据之后，一般会进行自下而上的聚合，比如按照产品、部门、团队、项目、应用等不同的维度聚合，这样就可以提供更高层级的视图进行展示和分析。而我们在分析效能问题时，更多是自上而下进行的，比如先看到整个公司的效能情况、各个部门的横向对比，然后再进行逐层下钻，一直到子部门、团队层级，甚至下钻到数据明细，从而从宏观到微观进行问题根因分析。&lt;/p&gt;
&lt;p&gt;在下面这个案例中，首先可以看到左上角的聚合数据报表，它展示了在所选时间范围内（周/月/季），所选部门与其同级部门的交付周期的横向比较，并且可以进行上一周期和本周期的对比。从这个宏观数据出发，我们可以进一步下钻分析，比如下钻到所选部门的下一级部门、下两级部门、下三级部门的数据图表，最终钻取到具体的明细数据。然后可以按照交付周期的长短对所选范围内的需求进行排序，并查看这些需求的交付过程和状态流转的细节，针对性分析影响效率的问题所在，寻求改善的抓手。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/26d2d7dba96b3b79c1ec5400847beb07.png&quot; alt=&quot;2023060545.png&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对在制品进行下钻&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们在做效能度量分析的时候，经常会按照固定周期（比如月度或季度）来统计效能数据、出具效能报告。但当每次看到效能报告中统计数据的时候，往往这个周期已经过去了。当我们根据上个周期的数据分析决定采取一些改进措施的时候，需要在下一个周期结束时才能进行效果验证，那么这就带来了一种延迟反馈。&lt;/p&gt;
&lt;p&gt;其实，我们也可以采取一些更积极的、更及时的分析和干预方法。比如前文中提到的流负载（或在制品）指标就是一种先导性指标，流负载过高一定会导致后续的交付效率下降、交付周期变长，所以识别到这类问题就要进行及时干预。那么如何干预呢？可以使用一种称为滞留时长报告（Aging Report）的下钻分析方法。&lt;/p&gt;
&lt;p&gt;工作项在交付管道中的停滞，会浪费交付过程中的宝贵时间。滞留时长报告显示了在交付管道中，没有完成的工作分别在当前状态滞留了多长时间。在下面这个案例中，我们首先可以看到左下角的流负载报表，它展示了在所选时间范围内（周/月/季），所选部门人均的在制品数量，并且可以进行上一周期和本周期的对比。从这个宏观数据出发，我们可以进一步下钻分析，比如下钻到所选部门的下一级部门、下两级部门、下三级部门的数据图表，最终钻取到具体的明细数据。这样我们就可以看到这些在制品的详细情况，它们目前分别处于什么样的阶段，在当前阶段已经滞留了多长时间。如果做得更好一些，可以计算出来工作项在每个阶段平均的滞留时长作为参考值，如果发现有些工作项滞留超过了平均时长，就需要特别进行关注，进一步分析是什么因素导致的阻塞，然后迅速采取行动，想办法恢复工作项的流动。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/2371327921952b1078e68e6967453957.png&quot; alt=&quot;2023060546.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3 相关性分析&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;软件研发效能的提升是复杂的，受到诸多因素的影响。这些因素与结果之间存在相关关系而不是因果关系。即使我们发现两组数据之间有关联，也不意味着其中一组必然会导致另一组。例如，如果某个团队 “代码技术债率”指标很高，一般情况下代表着代码中存在的很多问题被暂时搁置，未来持续维护的成本和技术风险很大，那么从较长一段周期的趋势来看，很有可能 “交付周期”的指标会持续增长，即两组指标之间存在相关性。但这并不是必然的因果关系，虽然技术债很多，但很有可能因为人员能力、突击加班等其他因素暂时掩盖了这种问题，表面上冲抵了这种趋势。&lt;/p&gt;
&lt;p&gt;但从研发效能分析的角度来看，我们仍然可以从历史数据中分析这种相关性，然后通过实验的方式进行探索，找到能够切实驱动效能提升的因素进行持续干预。比如，想提升线上质量、降低缺陷密度，经验告诉我们应该去加强单元测试的覆盖、完善 Code Review 机制、做好自动化测试案例的补充。但是，这真的有效么？我们通过数据来看，很可能没有任何效果！并不是说这些实践不该做，而是可能做的不到位。也许只是为了指标好看，编写缺少断言的单元测试、找熟人走过场分分钟通过的代码评审、覆盖一些非热点代码来硬凑测试覆盖率目标等等。所以，我们需要实验思维，要不断检视、反思、检讨所采用的实践，哪些实践的确有效，哪些实践效果不大，哪些实践方向正确但因执行不到位所以效果才不及预期。我们要通过实验找到那些真正有用的改进活动及其与结果之间的相关性关系，有的放矢采取行动才会更有效率和有效果。&lt;/p&gt;
&lt;p&gt;在下面这个案例中，我们的目标是降低需求交付周期。根据研发效能领域专家的经验和理论的输入，我们认为研发各阶段耗时、流负载、需求规模、紧急需求插入占比、需求变更率、变更前置时间、代码技术债率、缺陷解决时长、代码复杂度/重复度等指标与需求交付周期有正相关关系，而流动效率、需求评审通过率、代码评审通过率、发布成功率等指标与需求交付周期有负相关关系。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/5b8255cd94ec4925153e95a6f69d2c87.png&quot; alt=&quot;2023060547.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;然后，我们对过去半年的历史数据进行相关性分析并得到了一份相关性系数的热力图。在图中，正/负相关性由从浅到深的颜色进行标识，我们可以看到大部分相关性数据的计算结果与我们的经验和理论是匹配的，但也有个别数据与经验存在一定出入。那么接下来我们的行动思路也就明确了，即对已被数据证明存在相关性的活动和过程指标实施干预，如降低流负载、提升需求稳定性等，以期能够加速需求的交付速度。然后，对数据与经验有出入的指标进行检视与反思，分析是实践无效还是数据失真导致的误判，并在下个周期中进一步增加实验进行持续探查。&lt;/p&gt;
&lt;p&gt;以上分析过程体现了数据驱动、实验性的思维方式，这正是研发效能度量能够有效指导效能改进、促进效能提升的不二法门。&lt;/p&gt;
&lt;p&gt;另外，在这个案例中，我们还使用了北极星指标、群星指标与围栏指标的表述方式。上文已经讲到，北极星指标又称为首要关键指标（One Metric That Matters），可以用来指引我们改进的方向。为了进一步分解、分析北极星指标，我们还需要一些辅助性的参考指标，这些指标可能会有多个，分布在北极星指标的周围，我称之为群星指标。而围栏指标的设置是为了避免过度追求北极星指标所带来的潜在负面影响，避免在达成目标的解决方案选择上采取短视的行为。我们在分析一个特定场景时，可以使用由北极星指标、群星指标与围栏指标构成的指标集来进行全面的度量分析。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4 累积流图分析&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在上文的下钻分析一节中，我介绍了按阶段下钻的方法，可以把交付周期按照交付管道中不同节点，分解到每个阶段的耗时情况。但这种方法实际统计的是一段周期内的平均值，而平均值无法体现出按时间变化的趋势，只能用于事后分析，无法在过程中进行干预。接下来，让我们来细化和解决这一问题。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;累积流图&lt;/strong&gt;（CFD: Cumulative Flow Diagram)是一种很有效的度量分析方法，可以很好地反映工作项在每个流程节点的流动情况，观察到不同角色在交付过程中相互协作的情况，并可以很容易地分析出研发过程各个阶段在制品、交付周期、交付效率随时间变化的趋势。&lt;/p&gt;
&lt;p&gt;累积流图的 X 轴是日期，通常使用天数作为刻度，Y 轴的是工作项数量。那么 Y 轴从研发过程第一个状态（如“分析”）到最后一个状态（如“完成”）之间的高度，就代表了在制品的数量，高度越高说明在制品堆积越多。X 轴从研发过程第一个状态（如“分析”）到最后一个状态（如“完成”）之间的长度，则代表了从开发启动到完成的周期时间，这个长度越长说明周期时间越长，而这往往是由于在制品堆积造成的。根据利特尔法则，Throughput（吞吐量） = WIP（在制品） / Average Lead Time（平均前置时间）。在累积流图中，“完成”线的斜率就是吞吐量。通过观察“完成”线的斜率变化，就可以直观地看出团队的交付效率的变化。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/70c330526f09c587fd537ba5a22be9a5.png&quot; alt=&quot;2023060548.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在理解了以上分析方法后，我们就可以把工作项每个阶段的流动情况，按照时间维度绘制出来累积流图，来识别当前交付的进展、瓶颈、问题和需要进一步探查的内容。&lt;/p&gt;
&lt;p&gt;下图给出了研发效能度量平台绘制的四张典型的累积流图。我们来逐个分析一下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/f54f085056450972cd355a471bdaedf9.png&quot; alt=&quot;2023060549.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在左上角的累积流图中，我们发现代表”测试中”的红色区域随着时间推移，面积持续扩大，而且这个区域的高度和长度都在快速增长。这说明”测试中”这个状态的在制品堆积变得越来越严重，并且交付周期也在变得越来越长。我们初步可以判定”测试中”阶段可能是当前交付管道中的瓶颈所在。但这个时候还不能武断地认为就一定是测试资源或者测试产能的问题，还可能有各种其他情况。比如，开发提测质量很差导致大量缺陷产生，工作项虽然处于测试中状态但实际是在等待开发修复缺陷。或者是由于不同系统之间的依赖，已完成的部分不具备可独立测试性，需要等待其他系统就绪后才能开展测试等。但无论如何，我们已经找到了瓶颈点所在及其发展趋势，接下来的问题就是如何干预、优化和提升了。&lt;/p&gt;
&lt;p&gt;在右上角的累积流图中，我们发现代表了开发、测试、上线的多个阶段、不同颜色的区域都发生了”塌陷”，而工作项总量却保持稳定。这说明可能是多个阶段的状态发生了回退，比如某些需求虽然开发、测试完成，并且最终上线了，但是业务在线上验收的时候发现存在重大问题，或与原始需求目标存在较大差异，要求需求下线并重新进行设计和开发。这是一种严重的返工行为，我们知道这代表着巨大的研发资源浪费。这就是我们为什么要从源头把控好需求的质量，加强对需求的理解，明确需求验收条件的原因。如果是需求存在质量或歧义的问题，可能导致数倍于需求分析工作量的研发和测试工作量产生，这种杠杆作用会让本来就很稀缺的研发资源的有效产出进一步降低。研发效能不仅与效率有关，还关乎到有效性。&lt;/p&gt;
&lt;p&gt;在左下角的累积流图中，我们发现代表”开发中”的黄色区域随着时间推移，其高度保持水平，这说明”开发中”这个状态已经陷入了停滞。但代表”测试中”的绿色区域还在持续增长，说明并不是所有工作都停滞了。我们需要进一步探查发生这种情况的原因，由于并不是所有工作都停滞了，我们可以排除放长假的影响。所以，很有可能是开发过程中遇到了重大的技术架构问题，导致开发工作无法继续开展，或者由于出现了突发的紧急状况，需要调拨大量开发人员去进行救火，导致当前开发工作停滞。停滞作为流动的对立面，我们应当及时识别出这种情况，尽快处理。&lt;/p&gt;
&lt;p&gt;在右下角的累积流图中，我们看到除了“测试中”阶段出现在制品堆积问题以外，还发现在迭代后期有大量新增需求的情况发生，这有可能是为了响应业务的变化而进行紧急需求插入，也有可能是为了”搭车上线”，赶在发布窗口之前追加一些新的需求。敏捷思维让我们欣然接受需求的变更，但是我们也承认过度的变更会导致开发过程的摩擦。上线前出现大量需要搭车上线的需求也不一定都是合理的，很可能因开发和验证时间不充分导致线上问题，所以我们不能一味地接受，还有要进行合理的权衡。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5 流效率分析&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;流效率就是在交付管道中，工作项处于活跃工作状态的时间（无阻塞地工作）与总交付时间（活跃工作时间 + 等待时间）的比率。经验表明，很多企业的流效率只有不到 10%，也就意味着需求在交付管道中有大量时间都处于停滞、阻塞、等待的状态。&lt;/p&gt;
&lt;p&gt;我们结合 DevOps 平台中的看板工具，将待评审、就绪（待开发）、待测试、待发布等阶段的属性设置为”等待”，而需求沟通、需求评审、方案设计、开发、测试、发布等阶段的属性设置为”活跃”，这样就可以得到研发过程的基础数据，对流效率指标进行计算。&lt;/p&gt;
&lt;p&gt;下图给出了我在一个部门落地流效率度量和分析时的一些实施细节，通过对指定范围内团队的看板进行统一配置，明确各个阶段的准入准出，规范各个团队的操作规范，就可以得到流效率的度量数据。然后，我们通过对在制品数量进行控制、推进小批量交付和一系列最佳实践的引入，优化了研发阶段的等待时间，让流效率获得了一定的提升。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/c87acab482fa650808aa2c477e96b713.png&quot; alt=&quot;20230605410.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在这里有个问题需要特别注意，就是数据准确性的问题。如果依据看板工具进行各个研发阶段耗时的统计，那么我们就要考虑看板中的工作项状态与实际工作状态如何保持一致的问题。当然，办法还是有的。比如，我们可以依靠规范的宣贯和执行的监控，确保数据相对准确（例如至少在每日站会的时候确保工作项状态及时更新），但更为有效的办法是通过自动化的手段，在工作项与代码关联后，研发人员后续的一系列基于代码的提交、合并、提测、上线等动作可以自动联动更新工作项的状态，关于这部分的内容我们将在下一章中展开说明。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6 流负载分析&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;流负载是在交付管道中已经开始、尚未完成的工作项的数量，也就是我们经常说的在制品数量。流负载是一个关键的先导性指标，流负载过高一定会导致后续的交付效率下降、交付周期变长，所以识别到这类问题就要进行及时干预。&lt;/p&gt;
&lt;p&gt;下图给出了我在一个团队中落地流负载度量和分析时的一个案例，可以看到产研团队流负载比上个统计周期提升了 43%，而相同周期内的产研交付周期环比提升了近 20%。从实际统计数据来看，这两个指标之间存在关联关系，流负载的升高影响了交付周期的上浮。但这两个指标之间并没有像公式一样存在那种精确的数学关系，这是因为影响交付周期的因素本来就很多，我们无法像在实验室中一样屏蔽掉所有其他因素的影响，而只观察这两个指标之间的关系。另外，流负载的升高对于交付周期的上浮存在延迟反馈，积压的需求可能并没有在当前统计周期内完成，也就并没有进入到交付周期的数据统计范围内。但是，我们已经能足够清晰地看到趋势，两个指标之间存在强相关。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/28dbce86b2d104dca4885890540de46a.png&quot; alt=&quot;20230605411.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;看到了问题以后，我们可以使用上文中提到的在制品下钻方法进行具体工作项的排查。我们也可以使用被称为”个人研发日历”的视图进行查看。在下图中可以看到，位于最下面的开发人员在 3 月 15 日~3 月 21 日这周的并行任务非常多，而且都是贯穿整周时间的工作安排。这种大量并行，频繁打断和上下文切换的工作方式，也是研发过程中一种典型的浪费—任务切换浪费。我们应当进一步优化研发计划，控制并行的在制品，让流动变得更顺畅。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/ced94677b17845f305550c683b07c72a.png&quot; alt=&quot;20230605412.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;小结&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果一种度量真的很重要，那是因为它必须对决策和行为产生一些可以想象的影响。度量指标可以有很多，但如何用好这些指标识别、分析、诊断问题，并做出对效能提升有效的决策、牵引正确的行动才是重点。本文提出了六种常见的效能度量分析方法，虽然文中主要是以管理域的度量分析方法举例，但对工程域的分析（如代码、CI、测试等专项的分析）也是非常必要的，限于篇幅我们暂不展开，后续有机会再做介绍。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>研发效能度量的实践框架</title><link>https://blog.ithuo.net/posts/framework-for-measuring-r-d-team-performance/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/framework-for-measuring-r-d-team-performance/</guid><pubDate>Mon, 17 Apr 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;研发效能度量的成功落地需要一个相对完善的体系，其中包含数据采集、度量指标设计、度量模型构建、度量产品建设、数据运营等多个方面，我把它们整理出来形成一个实践框架，称为“研发效能度量的五项精进”。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/4b479b228c7c21303d7aded061c2a5ac.jpg&quot; alt=&quot;1725716193257.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 构建自动采集效能数据的能力&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;通过度量系统分层处理好数据接入、存储计算和数据分析。比如，小型团队通过 MQ、API 等方式把数据采集起来之后，使用 MySql（存放明细数据和汇总数据）、Redis（存放缓存数据）、ES（数据聚合和检索分析）三件套基本就够用了；而大规模企业由于数据量庞大、汇聚和分析逻辑复杂，建议使用整套大数据分析解决方案，比如流行的流批一体的大数据分析架构。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.设计效能度量指标体系&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;选取全局结果指标用于评估能力，局部过程指标用于指导分析改进。比如：需求交付周期、需求吞吐量就是全局结果指标，可用于对交付效率进行整体评估；交付各阶段耗时、需求变更率、需求评审通过率、缺陷解决时长就是局部过程指标，可用于指导分析改进。&lt;/p&gt;
&lt;p&gt;通过先导性指标进行事前干预，通过滞后性指标进行事后复盘。比如：流动负载（在制品数量）是一个先导性指标，根据利特尔法则，在制品过高一定会导致后续的交付效率下降、交付周期变长，所以识别到这类问题就要进行及时干预；而线上缺陷密度就是一个滞后性指标，线上缺陷已经发生了，我们能做的就只有复盘、对缺陷根因进行分析，争取在下个统计周期内能让质量提升、指标好转。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 建立效能度量分析模型&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这里的模型是指对研发效能问题、规律进行抽象后的一种形式化的表达方式。比如流时间（需求交付周期）、流速率（需求吞吐量）、流负载、流效率、流分布这五个指标结合在一起，就是一个典型的分析产品/团队交付效率的模型，通过这个模型可以讲述一个交付交付价值流完整的故事，回答一个关于交付效率的本质问题。&lt;/p&gt;
&lt;p&gt;模型还有很多种，比如组织效能模型（如战略资源投入分布和合理性）、产品/团队效能模型、工程师效能模型等，我们还要合理采用趋势分析、相关性分析、诊断分析等方法，分析效能问题、指导效能改进。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. 设计和实现效能度量产品&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;将数据转化为信息，然后将信息转化为知识，让用户可以自助消费数据，主动进行分析和洞察。&lt;/p&gt;
&lt;p&gt;简单的度量产品以展示度量指标为主，比如按照部门、产品线等维度进行指标卡片和指标图表的展现；做的好一点的度量产品可以加入各种分析能力，可以进行下钻上卷，可以进行趋势分析、对比分析等；而做的比较完善的度量产品应该自带各种分析模型和逻辑，面向用户屏蔽理论和数据关系的复杂性，直接输出效能报告，并提供问题根因分析和改进建议，让对效能分析不是很熟悉的人也能自助地使用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. 实现有效的效能数据运营体系&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;也许放在最后的其实才是最重要的，我们有了度量指标、有了度量模型、有了度量产品，但一定要注意的是：要避免不正当使用度量而产生的负面效果，避免将度量指标 KPI 化而导致“造数据&quot;的短视行为。根据古德哈特定律，度量不是武器，而是学习和持续改进的工具。&lt;/p&gt;
&lt;p&gt;正所谓“上有政策，下有对策&quot;，“度量什么就会得到什么&quot;，为了避免度量带来的各种副作用，我们首要的度量对象应该是工作本身，而不是工作者。另外，效能改进的运作模式也很重要，只是把数据报表放在那里效能不会自己变好，需要有团队或专人负责推动改进事宜。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;研发效能度量的指标体系设计&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;根据研发效能度量的七大原则，我们确定了从全局性出发，以结果产出为牵引的一系列研发效能度量指标 。这些指标也反映出了研发效能改进的关键点，即以端到端的流动效率（而非资源效率）为核心。这里的流动效率是指需求（或用户价值）在整个系统中跨越不同职能和团队流动的速度，速度越快则需求交付的效率越高、交付时长越短。当然我们并不是只关注流动效率、不关注资源效率（如工时、资源利用率等），而是在确保前者效率足够高的情况下再逐步提升后者，最终追求的是二者的协同优化。&lt;/p&gt;
&lt;p&gt;在建设初期，我们把研发效能度量指标分为三个维度，分别是交付效率、交付质量和交付能力。这些指标的提升需要组织进行管理、工程、技术等多方面的系统性改进。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/2bad76338b852692ef8538b7be6a4e77.jpg&quot; alt=&quot;1725716226982.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 交付效率&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;目标是促进端到端、及早的交付，用最短的时间顺畅地交付用户价值。具体可细分为以下指标：&lt;/p&gt;
&lt;p&gt;需求前置时间：也称为需求交付周期，是指从需求提出，到完成开发、测试，直到完成上线的时间周期。反映了整个团队（包含业务、产品、开发、测试、运维等职能）对客户问题或业务机会的交付速度，依赖整个组织各职能和部门的协调一致和紧密协作。从数据统计的角度来看，需求前置时间指标通常符合韦伯分布，我们要尽量避免度量的平均值陷阱，建议使用 85 百分位数进行统计分析，相关细节将在后续文章中展开说明。&lt;/p&gt;
&lt;p&gt;产研交付周期：从需求被产研团队确认，到完成开发、测试，直到完成上线的时间周期。反映了产研团队的交付速度，依赖需求的拆分和管理，研发团队的分工协作。&lt;/p&gt;
&lt;p&gt;需求吞吐量：统计周期内交付的需求个数 / 统计周期，即单位时间交付的需求个数。需要注意的是，需求颗粒度要保持一定规则（如约定业务需求、产品需求的颗粒度上限），避免需求大小不统一导致的数据偏差。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 交付质量&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;目标是促进端到端高质量交付，避免不必要的错误和返工。具体可细分为以下指标：&lt;/p&gt;
&lt;p&gt;线上缺陷密度：统计周期内线上或单个版本严重级别 Bug 数量 / 需求个数。&lt;/p&gt;
&lt;p&gt;故障恢复时间：线上系统和应用如果发生故障，多长时间可以进行恢复。&lt;/p&gt;
&lt;p&gt;变更成功率：上线部署成功，且没有导致服务受损、降级或需要事后补救的比例。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 交付能力&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;目标是建设卓越的工程能力，实现持续交付。具体可细分为以下指标：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;部署频率&lt;/strong&gt;：单位时间内的有效部署次数。团队对外响应的速度不会大于其部署频率，部署频率约束了团队对外响应和价值的流动速度。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;变更前置时间&lt;/strong&gt;：代码提交到功能上线的时长。反映了团队的工程技术能力，依赖交付过程中高度自动化以及架构、研发基础设施的支撑能力。&lt;/p&gt;
&lt;p&gt;我们落地的任何研发效率提升实践，推动的任何敏捷或 DevOps 转型，其目标都应该要促进交付效率、交付质量、交付能力中一个或多个要素的提升，而其中交付能力的提升通常需要一定的周期沉淀和积累，所以是延迟反馈的，但最终还是会体现在效率或质量的提升上。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;交付效率、交付质量、交付能力&lt;/strong&gt;的提升会推动软件研发效能的提升，而研发效能的提升最终会助力组织效能的提升和业务结果的优化。所以，我们在设计度量指标体系时，还应该增加业务结果维度的考量，包括业务价值、交付成本和满意度（包括客户满意度 NPS 及员工满意度 eNPS）。这样的指标体系才更完整，才更能体现出研发效能提升对于组织效能提升的贡献。所以，完整的指标维度设计应该是“3+1”的形式，即三个研发交付的维度，再加上一个业务结果的维度。&lt;/p&gt;
&lt;p&gt;研发效能度量指标体系的设计还要结合组织中实际的&lt;strong&gt;研发价值流&lt;/strong&gt;，并且在三个研发交付指标维度的基础之上，更多地考虑到价值的流动性，并增加相关的度量指标。下图展示了某互联网大厂典型的研发价值流，并且由此扩展出来一些新的度量指标项。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/6acb8324aa7f0b4720f7ce819049b823.png&quot; alt=&quot;2023060243.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在图中，我们可以看到存在两层价值流。第一层是需求价值流，流动的单元是业务需求，这是业务人员的核心关注点，目标是业务需求交付的效率和效果。主要节点包括：需求创建、需求受理、需求拆分和处理、需求开发测试并发布上线、需求发起验收，业务验收通过。第二层是产品交付价值流，流动的单元是业务需求拆解到叶子节点后形成的产品需求，目标是提高产品需求的持续交付能力，包括效率、质量和可预测性。产品需求由具体的敏捷交付团队承接，经过准备、评审、就绪、设计、开发、测试、发布等状态，直到完成。两层价值流之间存在承接和对齐的关联关系，产品需求的研发状态会回溯到业务需求层面进行信息同步。&lt;/p&gt;
&lt;p&gt;根据图中不同阶段的起始点，我们定义了多个周期类指标，包括端到端的交付周期和某个分段的交付周期。我们之前用文字描述的需求前置时间、产研交付周期在图中就可以展示的非常清晰。另外，我还特别绘制了一个虚线的管状图形，覆盖从需求受理到发布上线的过程，这就是我们重点要关注的交付管道。除了交付周期类指标（也称流时间）外，这里还有几个指标值得单独说明下：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;流速率&lt;/strong&gt;：单位时间内流经交付管道的工作项数量就是流速率，也就是我能常说的吞吐量。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;流分布&lt;/strong&gt;：单位时间内流经交付管道的需求中，不同工作项类型的占比（包括需求、缺陷、风险、技术债等）就是流分布，这个指标可以衡量团队工作量是花在开发新需求、被动救火还是主动解决技术债上，对于工作计划的合理分配有一定指导意义。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;流负载&lt;/strong&gt;：在交付管道中已经开始、尚未完成的工作项的数量就是流负载，其实就是我们经常说的在制品数量。流负载是一个关键的先导性指标，流负载过高一定会导致后续的交付效率下降、交付周期变长，所以识别到这类问题就要进行及时干预。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;流效率&lt;/strong&gt;：在交付管道中工作项处于活跃工作状态的时间（无阻塞地工作）与总交付时间（活跃工作时间 + 等待时间）的比率就是流效率。调查表明，很多企业的流效率只有不到 10%，也就意味着需求在交付管道中有大量时间都处于停滞、阻塞、等待的状态，以至于看似热火朝天的研发工作，很可能只是虚假繁忙。大家只是因为交付流被迫中断，所以切换到其他工作，从而并行开展了很多不同的工作而已，从业务和客户的视角来看，需求交付效率其实很低。&lt;/p&gt;
&lt;p&gt;流时间、流速率、流分布、流负载、流效率这五个指标结合在一起，就是一个典型的分析产品/团队交付效率的模型，通过这个模型可以讲述一个关于研发价值流完整的故事，回答一个关于交付效率的本质问题。&lt;/p&gt;
&lt;p&gt;截止到目前，我已经介绍了研发效能度量的一些比较关键的指标，这些指标通常已经能够用来评估产研团队的整体交付效率、交付质量和交付能力了。但是，我们不满足于可以评估效能，还要从宏观到微观一层层地下钻下去，找到那些影响效能的阻碍因素，这样才能针对性采取改进措施，让组织获得效能提升。因此，我整理了一张研发效能度量指标的“全景图”，希望对你有所帮助。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/5dcbd42578d55a4f9935c049f494994d.png&quot; alt=&quot;2023060244.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在图中，我以一种矩阵的形式来组织研发效能度量指标。纵轴是软件研发生命周期的各个阶段，横轴是研发效能度量的三大维度，矩阵中罗列了相关指标及其适用范围。图中实心的方框是偏结果性的指标，其他是偏过程性的指标。在落地过程中，我们的指标全集持续累积，实际上要多于图中展示的这些内容，这里只是给出一个示例，你可以结合所在组织的上下文进行进一步的增减和调整。&lt;/p&gt;
&lt;p&gt;除了以上指标，还有很多实践中常用的指标，这里选取一部分介绍下：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;需求规模&lt;/strong&gt;。用于描述需求的颗粒度，计算公式为：统计周期内交付的需求总研发工作量 / 需求个数。这个指标反映了产研团队需求拆分情况。对于单一团队来讲，需求规模保持相对稳定，需求吞吐量指标才具备参考意义。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;需求变更率&lt;/strong&gt;。统计周期内，发生变更的需求数与需求总数的占比。这个指标通过度量开发、测试过程中变更的需求数来达到衡量需求质量的目的。注意，这里的需求变更统计的是需求达到了就绪状态之后才发生的变更，主要用于反馈开发活动中实际发生的摩擦，这与敏捷拥抱变化的原则并不冲突。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;需求按时交付率&lt;/strong&gt;。统计周期内交付的需求中，满足业务方期望上线日期的需求个数占比。这个指标反映了在用户的视角下，产研团队是否在全力为满足业务方的上线需求而努力。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;技术债率&lt;/strong&gt;。技术债率是仓库维度的统计数据。计算公式为：预计技术债务修复时长占开发所有代码所需时间的比例。这个指标是有效衡量代码质量的一种方法，反映了因快速开发暂时不顾代码质量所产生的技术债比率，而技术债会不断降低开发效率。技术债本身无法在不同仓库之间比较，因为各个仓库大小各不相同，但技术债率就可以进行横向比较，因为比率是相对的。根据技术债率可以进行仓库的评级，对于直观体现仓库状况非常有帮助。关于这个指标更详细的信息可以参考：SQALE (Software Quality Assessment Based on Lifecycle Expectations)相关方法。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;单元测试覆盖率&lt;/strong&gt;。通过统计单元测试中对功能代码的行、分支、类等场景覆盖的比率，来量化说明测试的充分情况。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;平均缺陷解决时长&lt;/strong&gt;。用于描述研发修复线下缺陷的平均时长，计算公式为：统计周期内缺陷的总解决时间 / 缺陷数量。这个指标体现了研发解决线下缺陷的效率。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;代码评审覆盖率&lt;/strong&gt;。在主分支上，代码评审覆盖的提交数 / 总提交数。这个指标体现了研发质量内建活动中代码评审的总体执行情况，即有多少比例的提交被代码评审所覆盖。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;项目收益达成率&lt;/strong&gt;。收益指标全部完成的项目数 / 收益指标验证时间在所选周期内的项目数。这个指标衡量了项目的各项预期收益指标的达成情况。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;项目满意度评价&lt;/strong&gt;。以项目为维度，对该项目的整体过程进行评价，评价分为两层：第一层为总体满意度评价，用于对团队的整体交付情况进行评价；第二层为具体分类评价，用雷达图进行呈现，分类评价可用于收集改进意见，发现短板从而进行改进；分类评价包括但不限于以下几方面：需求管理、进度管理、成本管理、沟通管理、风险与问题管理、验收测试、上线质量、上线后支持、开放性问题等。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;实践者的常见困惑&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在指导团队进行指标设计的过程中，经常会遇到一些实践者的疑问，这也代表了一些对指标选取的常见困惑，主要有以下几点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;需求吞吐量是按需求个数算还是按故事点计算？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;针对这个问题，我建议还是应该按照需求个数来计算。敏捷中我们经常使用故事点来评估工作量的大小，大家已经使用的很成熟了。但故事点实际上是一种敏捷规划的工具，不建议作为需求吞吐量中关于需求规模的度量指标来使用。因为不同团队对于同样颗粒度大小的需求，所估算的故事点是不同的，所以不具备普适性和横向的可比性。&lt;/p&gt;
&lt;p&gt;另外，如果使用故事点来作为需求规模的度量指标，还会导致让研发人员产生规模冲动，想办法来增加估算的点数。这种行为又会导致业务人员/产品经理与研发之间产生不信任，对故事点数进行讨价还价和合同谈判的行为，从而导致了更多的问题。所以，一种比较建议的方式是，由产品经理和研发人员一起将需求拆分成颗粒度相对均匀的需求条目，然后用需求个数来表示需求规模，计算需求吞吐量。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;需求吞吐量计算时，需求大小不一怎么办？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这个问题其实紧接着上一个问题，如果使用需求个数来标识需求规模，计算需求吞吐量，那需求大小不一怎么办？这里的答案依然是需求的合理拆分，比如有的企业使用“业务需求-产品需求-技术任务”的三级需求层次模型来进行需求的分解，每一层的工作项条目都可以定义颗粒度范围，形成大小相对均匀的条目。比如业务需求最好能在一次发布中完成，产品需求最好在一个迭代内完成（如最多不超过 10 人天工作量），技术任务最好让研发能快速完成（如不超过 3 人天工作量）。&lt;/p&gt;
&lt;p&gt;把需求拆分为不同层次、相对均匀的工作项条目，一方面解决了度量准确性的问题（每个不同的层次可以分别统计），另外还有一个附加的好处是，这个指标会促使研发人员更有动力去更细地拆分需求，但这个副作用是对整个组织有利的，因为更小的需求可以更快地交付业务价值，这也是敏捷和精益思想中所提倡的。&lt;/p&gt;
&lt;p&gt;当然，最终拆分出来的需求大小也不可能完全一样，但是根据大数定理，只要样本足够多就能屏蔽个体的差异性而体现出整体的规律性。再者说，我们也不会只使用需求吞吐量这个单一指标去度量研发效能，而是结合交付周期类等一系列指标进行综合评估，所以也不必对这个指标的计算过于纠结。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;为什么度量变更前置时间，有什么意义？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;前文中我们也提到，变更前置时间度量的是代码提交到功能上线的时长。这个指标的意义在于它反映了团队的工程技术能力。软件研发不同于生产制造行业，后者在设计和生产计划制定后，基本上都是大规模、重复性、机械性的生产过程。而软件研发过程实际上可以分为两类活动：（1）创造性活动，比如基于业务需求进行创造性的设计和编码；（2）重复性活动，比如代码提交后进行重复性的构建、测试和部署。而第二个部分就是工程实践擅长的领域。&lt;/p&gt;
&lt;p&gt;软件研发同时受益于敏捷和精益方法。软件的二进制文件是敏捷方法创建的，而通往生产环境的路径是精益的，因为构建、测试、部署流程应该每天多次重复运行，并且具有高度的自动化。软件就是一种在精益流水线上，敏捷创建的盒子。&lt;/p&gt;
&lt;p&gt;我们可以问自己一个问题，如果你只修改了一行代码，那么从代码提交到上线需要多少时间？是几分钟，一个小时还是数天的时间？如果我们还在采用大量手工部署、手工测试、手工配置、复杂的审批流程，即使一行代码的变更也需要很久才能上线。所以回到问题本身，我们为什么要度量变更前置时间？因为我们希望通往生产环境的路径是精益的，这条路是被工程实践优化过的。所以，这个指标可以很好反应出团队的工程技术能力，让我们持续追求工程卓越（Engineering Excellence）。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;为什么度量平均故障恢复时间，而不是平均无故障时间？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在度量系统可靠性方面，有三个常见指标，分别是：MTTR、MTTF 和 MTBF。MTTF (Mean Time To Failure，平均无故障时间)，指系统无故障运行的平均时间，度量的是从系统开始正常运行到发生故障之间的时间段的平均值。MTTR (Mean Time To Repair，平均故障修复时间)，指系统从发生故障到修复完成之间的时间段的平均值，度量的是系统出现问题后恢复的速度。MTBF (Mean Time Between Failure，平均失效间隔)，指系统两次故障发生时间之间的时间段的平均值。MTBF= MTTF+ MTTR。&lt;/p&gt;
&lt;p&gt;在这三个指标中，为什么我们选用的是平均故障恢复时间（即 MTTR）呢？因为我们知道，在快速变更的复杂系统中，出错和故障是在所难免的。软件研发和运维的复杂性已经不仅限于系统架构的复杂性，还有像大型成熟企业普遍存在的历史包袱，新旧系统之间大量的信息通讯，复杂业务连接的多个不同系统，海量数据的计算与管理，跨团队协同等都可能是未知故障的触发点。所以核心的问题不是系统多长时间才出现故障，而是出现问题后如何快速恢复服务。&lt;/p&gt;
&lt;p&gt;所以，在接受了系统的复杂性与不确定性的前提下，业界一般优先选用平均故障恢复时间作为系统可靠性的核心度量指标。包括近年来流行的混沌工程，也是在追求如何实现复杂系统的韧性，这与我们度量指标的选择也是非常契合的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;小结&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;以上我们介绍了度量指标体系的设计思路，也展开对一些指标进行了详细说明。但是，这些度量指标并不是孤立存在的，它们之前存在很多相关性关系。如何综合选取适当的指标，并运用一系列统计分析方法进行效能的分析，才是用好这些指标的关键。我们将在下一节中详细讲解效能度量分析方法相关的内容。敬请期待！&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Golang开发环境配置</title><link>https://blog.ithuo.net/posts/golang-development-environment-configuration/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/golang-development-environment-configuration/</guid><pubDate>Sun, 15 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;推荐开发工具&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;jetbrains&lt;/strong&gt;家的&lt;a href=&quot;https://www.jetbrains.com/go/&quot;&gt;goland&lt;/a&gt; （四星）&lt;/p&gt;
&lt;p&gt;微软家的visual studio code (三星)&lt;/p&gt;
&lt;p&gt;从golang官网下载最新SDK安装包&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://go.dev/dl/&quot;&gt;All releases - The Go Programming Language&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;通常情况下，会因为网络原因无法从golang  module官网下载依赖，出现如下错误提示&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go: finding module for package rsc.io/quote
go: LearnApp imports
        rsc.io/quote: module rsc.io/quote: Get &quot;https://proxy.golang.org/rsc.io/quote/@v/list&quot;: dial tcp 172.217.160.113:443: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要配置代理&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;Go GOROOT 与 GOPATH 介绍
GOROOT：  GO 语言的安装路径。
GOPATH：若干工作区目录的路径 自己定义的工作空间。
GOBIN：GO 程序生成的可执行文件（executable file）的路径。&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;h3&gt;windows&lt;/h3&gt;
&lt;p&gt;打开你的终端并执行：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;go env -w GOPROXY=https://goproxy.cn,direct&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;macOS 或 Linux&lt;/h3&gt;
&lt;p&gt;打开你的终端并执行：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$ export GOPROXY=https://goproxy.cn&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;或者&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$ echo &quot;export GOPROXY=https://goproxy.cn&quot; &amp;gt;&amp;gt; ~/.profile &amp;amp;&amp;amp; source ~/.profile&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;完成。&lt;/p&gt;
&lt;h3&gt;查看修改效果&lt;/h3&gt;
&lt;h3&gt;&lt;code&gt;go env&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;环境变量设置&lt;/p&gt;
&lt;p&gt;&lt;code&gt;go env -w xxx=xxx&lt;/code&gt;
如&lt;/p&gt;
&lt;p&gt;&lt;code&gt;go env -w GO111MODULE=on&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这样就能正常下载golang的依赖包&lt;/p&gt;
&lt;p&gt;或者配置运行时代理&lt;/p&gt;
&lt;p&gt;创建&lt;code&gt;proxy_go.go&lt;/code&gt;文件&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;net/http&quot;
	&quot;os&quot;

	&quot;github.com/goproxy/goproxy&quot;
)

func main() {
	http.ListenAndServe(&quot;localhost:8080&quot;, &amp;amp;goproxy.Goproxy{
		GoBinEnv: append(
			os.Environ(),
			&quot;GOPROXY=https://goproxy.cn,direct&quot;, // Use Goproxy.cn as the upstream proxy
			&quot;GOPRIVATE=git.example.com&quot;,         // Solve the problem of pulling private modules
		),
		ProxiedSUMDBs: []string{
			&quot;sum.golang.org https://goproxy.cn/sumdb/sum.golang.org&quot;, // Proxy the default checksum database
		},
	})
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行命令运行，配置goland代理为“http://localhost:8080”&lt;/p&gt;
&lt;p&gt;&lt;code&gt;go run proxy_go.go&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;更详细的说明参考：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://goproxy.cn/&quot;&gt;Goproxy.cn&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>项目管理全流程图及详细管理过程</title><link>https://blog.ithuo.net/posts/project-management-full-process-and-detailed-procedures/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/project-management-full-process-and-detailed-procedures/</guid><pubDate>Sat, 07 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;项目管理流程&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;graph TD
    A[项目管理流程] --&amp;gt; B[启动]
    B --&amp;gt; C[计划]
    C --&amp;gt; D[执行]
    D --&amp;gt; E[控制]
    E --&amp;gt; F[结尾]
    
    B --&amp;gt; G[制定项目章程并确定初步范围&amp;lt;br&amp;gt;需求与目标&amp;lt;br&amp;gt;范围与成功&amp;lt;br&amp;gt;明确项目组员]
    C --&amp;gt; H[制定项目管理计划&amp;lt;br&amp;gt;工作计划分解&amp;lt;br&amp;gt;进度计划&amp;lt;br&amp;gt;沟通计划]
    D --&amp;gt; I[指导管理项目执行活动&amp;lt;br&amp;gt;资源调配&amp;lt;br&amp;gt;领导团队沟通解决进度&amp;lt;br&amp;gt;把控项目变更]
    E --&amp;gt; J[监控项目执行并进行整体变更控制]
    F --&amp;gt; K[项目收尾和结束&amp;lt;br&amp;gt;审核确认&amp;lt;br&amp;gt;评估验收项目&amp;lt;br&amp;gt;总结文档归档]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;启动&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;graph TD
    A[启动] --&amp;gt; B[启动内容]
    A --&amp;gt; C[项目经理责任]
    A --&amp;gt; D[项目组成员责任]
    A --&amp;gt; E[启动阶段三个关键点]
    A --&amp;gt; F[启动阶段常见问题]

    B --&amp;gt; B1[1. 明确项目需求]
    B --&amp;gt; B2[2. 确定项目目标]
    B --&amp;gt; B3[3. 定义项目相关方的期望值]
    B --&amp;gt; B4[4. 描述基本的项目范围]
    B --&amp;gt; B5[5. 选择基本的项目组成员]
    B --&amp;gt; B6[6. 明确项目经理]
    B --&amp;gt; B7[7. 确认要交付的文档]
    B --&amp;gt; B8[8. 由管理层、项目经理确认]

    C --&amp;gt; C1[1. 与客户沟通协商，明确项目需求和所需资源等]
    C --&amp;gt; C2[2. 在项目实施过程中不断了解客户需求]
    C --&amp;gt; C3[3. 保证与项目相关方的沟通并汇报项目进程]
    C --&amp;gt; C4[4. 挑选项目组成员，得到项目组的支持服务]
    C --&amp;gt; C5[5. 项目计划过程中领导和指导项目组成员服务]
    C --&amp;gt; C6[6. 挑选控制项目进程，保证项目按时间计划执行]

    D --&amp;gt; D1[1. 参与项目计划的制定]
    D --&amp;gt; D2[2. 服从项目经理的指挥，执行计划分配的任务]
    D --&amp;gt; D3[3. 保持与项目经理的沟通]
    D --&amp;gt; D4[4. 配合其他小组成员的工作]
    D --&amp;gt; D5[5. 项目核心成员对项目经理负责，保证的完成]

    E --&amp;gt; E1[1. 与客户、高层间沟通，明确项目需求并获得相关支持]
    E --&amp;gt; E2[2. 明确项目需求和目标]
    E --&amp;gt; E3[3. 开会讨论，明确团队并执行相关要求]

    F --&amp;gt; F1[需求不明确及需要沟通不够]
    F --&amp;gt; F2[项目组成员的选择]
    F --&amp;gt; F3[为促成项目，过于乐观地分析可行性]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;计划&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;graph TD
    A[2 计划] --&amp;gt; B[计划内容]
    A --&amp;gt; C[计划阶段]
    
    B --&amp;gt; B1[具体工作任务和执行次序风险分析]
    B --&amp;gt; B2[风险分析]
    B --&amp;gt; B3[得到相应的项目相关方批准的项目计划]
    B --&amp;gt; B4[工具: 甘特图, 里程碑, 网络图, 思维导图]
    
    C --&amp;gt; C1[管理计划 时间, 范围, 风险, 沟通等]
    C --&amp;gt; C2[工作任务分解]
    C --&amp;gt; C3[任务工期估算]
    C --&amp;gt; C4[时间进度安排]
    C --&amp;gt; C5[风险与沟通计划]
    C --&amp;gt; C6[项目预算计划]
    C --&amp;gt; C7[明确项目范围及具体任务]
    C --&amp;gt; C8[全面的风险识别]
    C --&amp;gt; C9[各关键人员的识别与沟通计划]
    
    B --&amp;gt; D[三个关键点]
    D --&amp;gt; D1[主要任务]
    D --&amp;gt; D2[主要成果]
    D --&amp;gt; D3[常见问题]
    
    D2 --&amp;gt; E[任务分解计划]
    D2 --&amp;gt; F[时间进度计划]
    D2 --&amp;gt; G[沟通计划]
    
    D3 --&amp;gt; H[对工作任务分解不充分]
    D3 --&amp;gt; I[风险意识不强, 没有沟通计划]
    D3 --&amp;gt; J[计划缺乏个人责任, 项目组没有共识认识]
    
    K[工作任务分解] --&amp;gt; L[1. 你的项目目标是什么?项目目标的具体任务你怎么分?]
    K --&amp;gt; M[2. 分解的原则需全方位, 彻底独立]
    K --&amp;gt; N[3. 分解的方法自上而下, 头脑风暴]
    K --&amp;gt; O[4. 表达的形式]
    K --&amp;gt; P[5. 最小粒度的特征]
    
    P --&amp;gt; P1[一个清晰任务的完成]
    P2[一个清晰的责任人]
    P3[时间估算工期和工作量]
    
    Q[根据项目任务的执行顺序, 时间计划及所需资源来进行分析, 制定计划] --&amp;gt; R[进度计划] --&amp;gt; S[主要工具]
    
    S --&amp;gt; S1[甘特图 工作分解结构WBS, 责任分配矩阵RAM]
    S --&amp;gt; S2[里程碑]
    S --&amp;gt; S3[网络图]
    
    R --&amp;gt; T[风险计划]
    
    T --&amp;gt; T1[1. 识别风险]
    T --&amp;gt; T2[2. 评估风险等级]
    T --&amp;gt; T3[3. 制定风险的应对计划]
    T --&amp;gt; T4[4. 制定所有计划中有可能出现的风险]
    T --&amp;gt; T5[5. 分析执行中可能会出现的问题]
    T --&amp;gt; T6[6. 与项目组员一一头脑风暴]
    T --&amp;gt; T7[7. 回顾以往项目中曾出现的问题三大类别: 交期, 准确, 给到评价]
    
    R --&amp;gt; U[沟通计划]
    
    U --&amp;gt; U1[沟通计划是根据项目任务的执行顺序, 时间计划及所需资源来进行分析, 制定计划]
    
    V[四个沟通渠道] --&amp;gt; V1[正式沟通在项目的时间节点上, 通过正式的渠道传达给项目相关人, 开展必要的沟通活动]
    
    W[如何指定项目沟通制度?]
    
    W --&amp;gt; W1[程序干系人]
    W --&amp;gt; W2[所需信息]
    W --&amp;gt; W3[频率]
    W --&amp;gt; W4[方法]
    W --&amp;gt; W5[责任人]
    
    X[高层管理] --&amp;gt; X1[项目进度, 成本, 进度, 质量及效益情况]
    X --&amp;gt; X2[每月]
    X --&amp;gt; X3[报告会议]
    X --&amp;gt; X4[项目经理]
    
    Y[职能管理] --&amp;gt; Y1[问题及目标行为]
    Y --&amp;gt; Y2[每周]
    Y --&amp;gt; Y3[报告会议]
    Y --&amp;gt; Y4[项目经理]
    
    Z[实施] --&amp;gt; Z1[视导团队]
    Z --&amp;gt; Z2[促进解决问题]
    Z --&amp;gt; Z3[和谐队伍氛围]
    Z --&amp;gt; Z4[保证计划所需的资源]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;执行&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;graph TD
    A[3 执行] --&amp;gt; B[项目沟通要点]
    B --&amp;gt; C[项目组成员对目标达成共识]
    B --&amp;gt; D[相互尊重]
    B --&amp;gt; E[项目沟通计划、规章]
    B --&amp;gt; F[主动倾听]
    
    A --&amp;gt; G[项目人员沟通]
    G --&amp;gt; H[项目组内沟通]
    G --&amp;gt; I[高层客户沟通]
    
    H --&amp;gt; J[四个主要沟通需求:&amp;lt;br&amp;gt;职责、授权、协调、状态]
    H --&amp;gt; K[会议: 项目讨论会、&amp;lt;br&amp;gt;成员进度汇报、&amp;lt;br&amp;gt;项目例会及时、公开、&amp;lt;br&amp;gt;检讨好处]
    
    I --&amp;gt; L[谁, 为什么需要信息?&amp;lt;br&amp;gt;他们需要什么类型的信息?何种相近程度, 频率?&amp;lt;br&amp;gt;当你和高层及客户沟通时, 你的目标是什么?&amp;lt;br&amp;gt;采用什么样的方法完成沟通?]
    
    A --&amp;gt; M[项目会议沟通]
    M --&amp;gt; N[会前]
    M --&amp;gt; O[会中]
    M --&amp;gt; P[会后]
    
    N --&amp;gt; Q[明确为什么开会, 以及预期获得什么效果.]
    N --&amp;gt; R[考虑是否可以取消会议]
    N --&amp;gt; S[确定要参加的最少人数]
    N --&amp;gt; T[确认会议室]
    N --&amp;gt; U[和关键与会者就会议议题及持续时间进行沟通]
    
    O --&amp;gt; V[做好准备按时开始, 首先说明会议目的、会议议题]
    O --&amp;gt; W[每位与会者都有发言机会]
    O --&amp;gt; X[对会议内容进行口头总结]
    
    P --&amp;gt; Y[会后发布会议纪要给每位参会者]
    P --&amp;gt; Z[会议必须产生明确的决定]
    P --&amp;gt; AA[所有决定必须建立即时清单]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;控制&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;graph TD
    A[4 控制] --&amp;gt; B[控制内容]
    B --&amp;gt; C1[1识别计划的偏离]
    B --&amp;gt; C2[2采取矫正措施, 使实际进展与计划保持一致]
    B --&amp;gt; C3[3接受和评估相关方的项目变更请求]
    B --&amp;gt; C4[4必要时重新调整项目活动]
    B --&amp;gt; C5[5必要时调整资源水平]
    B --&amp;gt; C6[6得到授权者批准后, 变更项目范围, 调整项目目标并记录]
    B --&amp;gt; C7[7监控项目进展, 把控项目实施]

    A --&amp;gt; D[监控要点]
    D --&amp;gt; E1[高风险任务]
    D --&amp;gt; E2[资源费用]
    D --&amp;gt; E3[项目进度]
    D --&amp;gt; E4[人员表现]

    A --&amp;gt; F[方法工具]
    F --&amp;gt; G[方法和工具]
    G --&amp;gt; G1[1. 项目进度计划表]
    G --&amp;gt; G2[2. 百分会议]
    G --&amp;gt; G3[3. 观察/检查]
    G --&amp;gt; G4[4. 跟踪行动计划]
    G --&amp;gt; G5[5. 定期反馈及报告]
    G --&amp;gt; H[1、投入更多的人&amp;lt;br&amp;gt;2、现有的人投入更多时间（加班）&amp;lt;br&amp;gt;3、换工作效率更高的人去做&amp;lt;br&amp;gt;4、改进方法和工具，提高效率&amp;lt;br&amp;gt;5、缩小项目范围或降低活动质量&amp;lt;br&amp;gt;需要求监控过程中发现进度延迟怎么办]

    I[客户方: 不断变化的想法与欲望] --&amp;gt; J[变更管理]
    K[项目团队: 成员技能与团队冲突] --&amp;gt; J
    L[项目优先级: 资源变化, 其他项目影响] --&amp;gt; J

    M[根据沟通计划, 与项目相关方进&amp;lt;br&amp;gt;行良好沟通] --&amp;gt; N[三个关键点]
    O[严格监控进度, 及时协调解决问&amp;lt;br&amp;gt;题] --&amp;gt; N
    P[重点跟踪监控高风险任务, 并采&amp;lt;br&amp;gt;取有效的防范措施] --&amp;gt; N

    N --&amp;gt; Q[执行与监控阶段]
    Q --&amp;gt; R[常见问题]
    R --&amp;gt; S1[需求变更管理不善, 导致变更频&amp;lt;br&amp;gt;繁, 项目组运作混乱]
    R --&amp;gt; S2[跨部门项目组成员的绩效考核与&amp;lt;br&amp;gt;激励机制不完善]
    R --&amp;gt; S3[项目组的沟通和跨部门协作难度&amp;lt;br&amp;gt;比较大]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;收尾&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;graph TD
    A[5 收尾] --&amp;gt; B[收尾流程]
    B --&amp;gt; C[评估及验收]
    B --&amp;gt; D[项目总监]
    B --&amp;gt; E[领导审核并确认]
    B --&amp;gt; F[文档归档]

    G[项目结束] --&amp;gt; H[01财务: 评估投资回报率, 评估实际费用与计划费用]
    G --&amp;gt; I[02时间: 与计划的一致性]
    G --&amp;gt; J[03质量: 项目输出的表现水平, 客户对质量的感受]
    G --&amp;gt; K[04人力资源: 团队精神, 激励, 态度调查]
    G --&amp;gt; L[05环境: 环境因素对项目活动的影响]
    G --&amp;gt; M[06项目计划: 计划流程的费用评估及适当的管理技术的使用]

    N[归档文档] --&amp;gt; O[启动]
    N --&amp;gt; P[计划执行]
    N --&amp;gt; Q[监控]
    N --&amp;gt; R[收尾]

    O --&amp;gt; S[方案合同项目基本信息表]
    P --&amp;gt; T[阶段时间安排项目综合计划表等]
    Q --&amp;gt; U[项目会议纪要变更说明, 审核记录, 阶段性报告, 相关文献]
    R --&amp;gt; V[项目结果文档, 项目评审验收报告, 项目总结报告, 项目交付的其他文档]

    B --&amp;gt; W[收尾内容]
    W --&amp;gt; X[项目总结]
    W --&amp;gt; Y[项目收尾分类]

    X --&amp;gt; Z[项目总结表 (项目总结, 问题与收获, 贡献度)]
    Y --&amp;gt; AA[合同收尾]
    Y --&amp;gt; AB[行政收尾]

    AC[三个关键点] --&amp;gt; AD[顺利完成项目评估和验收]
    AC --&amp;gt; AE[项目总结, 经验总结]
    AC --&amp;gt; AF[完整的项目信息规定]

    AG[收尾阶段] --&amp;gt; AH[常见问题]
    AH --&amp;gt; AI[经验教训的总结不够]
    AH --&amp;gt; AJ[项目组成员对项目的重要性认识不足]
    AH --&amp;gt; AK[项目的移交]
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>Derick</author></item><item><title>如何保护敏感数据</title><link>https://blog.ithuo.net/posts/how-to-protect-sensitive-data/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/how-to-protect-sensitive-data/</guid><pubDate>Tue, 03 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;当我们将敏感数据托付给系统时，我们期望它们能够保证数据的安全和保护。数据泄露可能对组织及其客户产生毁灭性的影响，从财务损失到声誉损害都有可能。公司可以使用多种技术来保护客户的敏感数据，但在我们探讨这些方法之前，首先让我们定义一下什么是敏感数据。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/11fbb054a3b5507df3a56be61c6e9954.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;确定系统中运行的敏感数据是关键，因为这有助于你明确安全工作的范围。大多数数据保护技术都带有相当大的开销，这就是为什么在不需要的数据和系统上实施安全工作并不理想。此外，应彻底审计存储的数据，并避免存储不必要的敏感信息，例如那些可以从第三方服务获取的信息；这可以减少你的安全需求。&lt;/li&gt;
&lt;li&gt;加密是数据保护的典型策略。它在静态（数据存储在数据库中）和传输（通过网络发送）时进行，使用如 TSL 等协议。即使数据被泄露或拦截，加密也使得除了那些被授权查看的人之外，任何人都无法阅读。&lt;/li&gt;
&lt;li&gt;密码学在几乎每一种数据保护策略中都被大量使用。它在加密、密钥管理、数字签名等方面得到了实施。在使用密码学算法时，最好依赖于成熟且维护良好的库，如 OpenSSL，而不是自己构建。为了抵御暴力攻击，应使用故意慢的密钥派生函数。此外，向哈希函数引入随机数据，或者&quot;盐&quot;，使得攻击者解密显著更具挑战性。&lt;/li&gt;
&lt;li&gt;强大的访问控制至关重要。用于加密的密钥应定期更换，所有请求都应被认证，而且应使用最小权限原则限制对敏感数据的访问。&lt;/li&gt;
&lt;li&gt;就像加密一样，令牌化通过替换数据来保护数据，使其对未经授权的方无法使用，而不是限制对其的访问。它通过用占位符，或者&quot;令牌&quot;，替换敏感数据来实现这一点。这些令牌没有固有的价值，而且在没有访问特定令牌化系统的情况下，不能被还原到原始形式。在 FinTech 中，令牌化是一种常见的做法，用于避免在服务之间共享信用卡信息。&lt;/li&gt;
&lt;li&gt;备份系统在数据保护计划中往往会被忽视。重要的是要确保在主数据库上实施的安全策略也在备份存储系统上得到实施。&lt;/li&gt;
&lt;li&gt;进行定期的审计是必要的，以确保系统符合最新和最有效的安全实践。通过持续的监控，技术团队可以在它们成为主要威胁之前，识别并解决潜在的漏洞。此外，持续的培训和教育对于提高技术团队的技能以及了解新出现的安全威胁至关重要。&lt;/li&gt;
&lt;li&gt;保护敏感数据远非&quot;设定并忘记&quot;的任务，它需要一个持续的过程，需要在全方位上对安全进行承诺。高度安全的系统往往有一个共同点——他们的技术团队将安全融入到他们的文化中；从他们设计解决方案的方式，到他们进行代码审查的方式[1][2][3][4][5]。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.congruity360.com/blog/ways-to-protect-your-sensitive-data/&quot;&gt;https://www.congruity360.com/blog/ways-to-protect-your-sensitive-data/&lt;/a&gt;
[2] &lt;a href=&quot;https://www.upguard.com/blog/protecting-sensitive-data&quot;&gt;https://www.upguard.com/blog/protecting-sensitive-data&lt;/a&gt;
[3] &lt;a href=&quot;https://www.polar.security/post/how-to-protect-sensitive-data&quot;&gt;https://www.polar.security/post/how-to-protect-sensitive-data&lt;/a&gt;
[4] &lt;a href=&quot;https://www.weber.edu/iso/protecting-sensitive-data.html&quot;&gt;https://www.weber.edu/iso/protecting-sensitive-data.html&lt;/a&gt;
[5] &lt;a href=&quot;https://www.american.edu/oit/security/protecting-sensitive-data.cfm&quot;&gt;https://www.american.edu/oit/security/protecting-sensitive-data.cfm&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>数据库扩展的五大技术</title><link>https://blog.ithuo.net/posts/five-technologies-for-database-expansion/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/five-technologies-for-database-expansion/</guid><pubDate>Sun, 01 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;应用程序最初并不是为了处理高流量而设计的。这就是为什么随着用户基数的增长，系统会经历显著的瓶颈。&lt;/p&gt;
&lt;p&gt;最常见的瓶颈罪魁祸首是数据库。&lt;/p&gt;
&lt;p&gt;在扩展系统时，专注于数据库的解决方案往往是最容易采取的措施。&lt;/p&gt;
&lt;p&gt;在我们深入探讨扩展数据库的最佳选项之前，重要的是要注意，系统不应该过早地进行优化。这是因为扩展解决方案往往会引入以下复杂性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;系统变得更加复杂，涉及更多的部分和变量。&lt;/li&gt;
&lt;li&gt;添加新功能所需的时间变长，因为需要考虑更多的组件。&lt;/li&gt;
&lt;li&gt;随着需要适应更多边缘情况，代码可能更难测试。&lt;/li&gt;
&lt;li&gt;发现和解决错误变得更加复杂。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为了交付一个性能合理的系统，以下五种数据库扩展技术值得考虑。&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;缓存数据库查询&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;缓存数据库查询是你可以对数据库负载进行的最简单的改进之一。通常，一个应用程序会有少数几个查询构成了请求的大多数。&lt;/p&gt;
&lt;p&gt;与其每次都通过网络往返获取数据，不如简单地在网络服务器上的内存中缓存它。&lt;/p&gt;
&lt;p&gt;第一个请求将从数据库获取数据并在服务器上缓存结果，未来的请求只需从缓存中读取。这样可以提高性能，因为数据在网络中的传输时间减少了，而且更接近客户端。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/18ce54c962ee1327610b0102d5476401.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;数据库索引&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;数据库索引是一种提高数据库表数据检索操作速度的技术。索引用于快速定位数据，而无需每次访问表时都搜索表中的每一行。&lt;/p&gt;
&lt;p&gt;根据表中的行数，这可以为使用索引列的查询节省大量时间。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/4da6fcfe7354e358f2b7a8c425ecda4e.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;移动会话数据&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;许多应用程序在 cookie 中保存会话 ID，实际的会话数据则保存在数据库表中。这给数据库带来了很大的负载。一种替代方案是将会话数据转移到像 Redis 或 Memcached 这样的内存缓存中。虽然这提高了访问速度，但如果缓存宕机，数据可能会丢失。另一种方法是使用 JWT，它允许你直接在 cookie 中存储会话详情，减少了服务器端会话的依赖，但它也有自己的一套问题。&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;数据库读取复制&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;如果在缓存常见查询、创建高效索引和处理会话存储之后，数据库仍然承受着过多的读取负载，复制可能是下一个最佳解决方案。&lt;/p&gt;
&lt;p&gt;通过读取复制，一个主数据库处理写入操作，而几个副本（在不同的机器上）处理读取操作。这种设置提高了写入性能，分散了读取负载，并通过在不同地区放置副本来优化读取速度。然而，可能会存在数据不一致性，因为写入的数据传播到副本需要时间。对于实时更新，比如立即渲染个人资料，你可以从主数据库读取。尽管读取复制提供了强大的扩展优势，但它也有复杂性。在尝试更简单的解决方案后，再考虑这种方法。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/263125627d90a789f272e88e70068b07.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;数据库分片&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;大多数扩展方法都集中在管理数据库读取上。数据库分片旨在通过将主数据库分割成更快、更易管理的“分片”来解决读取和写入问题。&lt;/p&gt;
&lt;p&gt;有两种分片技术可用：水平和垂直。水平分片将表分布在不同的机器上，这些机器具有相同的列但唯一的行。垂直分片将一个表分割成不同的表，分布在不同的机器上，每个表都有唯一的行和列。&lt;/p&gt;
&lt;p&gt;分片提高了查询速度，并增强了系统对故障的抵抗力。在分片设置中，通常只有一个分片受到影响，而不是整个系统。&lt;/p&gt;
&lt;p&gt;尽管分片提供了显著的好处，但它增加了很多复杂性，这意味着高昂的设置和维护成本。在其他扩展解决方案都已耗尽后，应考虑分片。&lt;/p&gt;
&lt;p&gt;数据管理系统在不断发展和增长，开辟了其他扩展数据库的技术。尽管有许多替代方案，但上述五种技术将继续是适用于现在和未来大多数用例的强大技术。&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.mongodb.com/basics/scaling&quot;&gt;https://www.mongodb.com/basics/scaling&lt;/a&gt;
[2] &lt;a href=&quot;https://www.freecodecamp.org/news/understanding-database-scaling-patterns/&quot;&gt;https://www.freecodecamp.org/news/understanding-database-scaling-patterns/&lt;/a&gt;
[3] &lt;a href=&quot;https://www.codecademy.com/article/database-scaling-strategies&quot;&gt;https://www.codecademy.com/article/database-scaling-strategies&lt;/a&gt;
[4] &lt;a href=&quot;https://thenewstack.io/techniques-for-scaling-applications-with-a-database/&quot;&gt;https://thenewstack.io/techniques-for-scaling-applications-with-a-database/&lt;/a&gt;
[5] &lt;a href=&quot;https://realscale.cloud66.com/database-server-scaling-strategies/&quot;&gt;https://realscale.cloud66.com/database-server-scaling-strategies/&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>SSL和TLS</title><link>https://blog.ithuo.net/posts/ssl-and-tls/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/ssl-and-tls/</guid><pubDate>Fri, 30 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;SSL（安全套接字层）和 TLS（传输层安全）是为了在网络上提供安全通信而设计的加密协议。TLS 是 SSL 的后继者，解决了 SSL 中存在的漏洞。&lt;/p&gt;
&lt;p&gt;为了理解它们的区别，让我们来看看使用这些协议发送数据的工作流程：&lt;/p&gt;
&lt;h3&gt;𝟭) 初始化通信&lt;/h3&gt;
&lt;p&gt;SSL 和 TLS：在数据可以发送之前，必须首先建立连接。在这个阶段，两种协议的工作方式非常相似。客户端和服务器建立连接，通常在端口 443 上进行网络流量（HTTPS 的默认端口）。&lt;/p&gt;
&lt;h3&gt;𝟮) ClientHello 和 ServerHello 消息&lt;/h3&gt;
&lt;p&gt;在建立连接后，客户端和服务器需要就安全设置达成一致。
SSL：客户端发送支持的密码套件列表和其他设置。然后，服务器发送响应，选择 SSL 版本、密码套件和其他设置。
TLS：除了支持的密码套件和其他设置外，客户端还可以发送 Diffie-Hellman（DH）或椭圆曲线 Diffie-Hellman（ECDH）的 &quot;key share&quot;（如果支持）。然后，服务器发送响应，选择 TLS 版本、密码套件和其他设置。&lt;/p&gt;
&lt;h3&gt;𝟯) 服务器证书&lt;/h3&gt;
&lt;p&gt;SSL 和 TLS：在 &quot;ClientHello&quot; 和 &quot;ServerHello&quot; 消息通信后，服务器将其数字证书发送给客户端。&lt;/p&gt;
&lt;h3&gt;𝟰) 密钥交换&lt;/h3&gt;
&lt;p&gt;在这个阶段，两种协议有显著的不同。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SSL：主要使用 RSA 进行密钥交换。&lt;/li&gt;
&lt;li&gt;TLS：使用其他机制，如 DH 和 ECDH。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;𝟱) 客户端证书（可选）&lt;/h3&gt;
&lt;p&gt;SSL 和 TLS：在交换密钥后，如果服务器需要验证客户端的身份，可以请求客户端证书。&lt;/p&gt;
&lt;h3&gt;𝟲) 客户端和服务器完成消息&lt;/h3&gt;
&lt;p&gt;SSL 和 TLS：一旦认证阶段完成，就会发送 &quot;Finished&quot; 消息。这两种协议在这里的唯一区别是，消息背后的加密计算可能会有所不同。&lt;/p&gt;
&lt;h3&gt;𝟳) 加密数据传输&lt;/h3&gt;
&lt;p&gt;已经建立了连接，达成了设置协议，完成了认证 — 数据传输终于可以开始了。
SSL：使用较旧的加密算法，其中一些是易受攻击的。
TLS：使用更新和更强大的加密算法。&lt;/p&gt;
&lt;h3&gt;𝟴) 终止&lt;/h3&gt;
&lt;p&gt;SSL 和 TLS：在数据传输完成后，客户端和服务器可以发送警报消息以终止连接。&lt;/p&gt;
&lt;p&gt;虽然 SSL 和 TLS 协议有许多相似之处，但 TLS 已经克服了 SSL 带来的漏洞。TLS 中使用的精细数字握手、密钥交换机制和加密方法，使得加密更强大，安全性更高，可扩展性更好。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/61d4360c352b7c3ccc8b4a46d11bff45.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.keyfactor.com/blog/ssl-vs-tls-what-are-the-differences/&quot;&gt;https://www.keyfactor.com/blog/ssl-vs-tls-what-are-the-differences/&lt;/a&gt;
[2] &lt;a href=&quot;https://www.ssl2buy.com/wiki/ssl-vs-tls&quot;&gt;https://www.ssl2buy.com/wiki/ssl-vs-tls&lt;/a&gt;
[3] &lt;a href=&quot;https://aws.amazon.com/compare/the-difference-between-ssl-and-tls/&quot;&gt;https://aws.amazon.com/compare/the-difference-between-ssl-and-tls/&lt;/a&gt;
[4] &lt;a href=&quot;https://security.stackexchange.com/questions/5126/whats-the-difference-between-ssl-tls-and-https&quot;&gt;https://security.stackexchange.com/questions/5126/whats-the-difference-between-ssl-tls-and-https&lt;/a&gt;
[5] &lt;a href=&quot;https://www.reddit.com/r/cryptography/comments/alas4q/tls_vs_ssl_difference/?rdt=58024&quot;&gt;https://www.reddit.com/r/cryptography/comments/alas4q/tls_vs_ssl_difference/?rdt=58024&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>如何考虑选择单体架构还是微服务</title><link>https://blog.ithuo.net/posts/how-to-choose-monolithic-architecture-or-microservices/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/how-to-choose-monolithic-architecture-or-microservices/</guid><pubDate>Tue, 27 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在开始之前，为什么你应该关心？系统设计决策很重要，因为一旦决定了很难改变。需要仔细考虑以确保你的系统能满足需求。&lt;/p&gt;
&lt;p&gt;单体架构与微服务架构正是这样一个例子。&lt;/p&gt;
&lt;p&gt;单体架构是一种软件设计模式，所有应用程序组件合并成一个紧密耦合的统一应用程序。&lt;/p&gt;
&lt;p&gt;而在微服务设计中，应用程序的组件被构建为一系列松散耦合、可独立部署的服务。每个服务对应一个特定的业务功能。&lt;/p&gt;
&lt;p&gt;例如，假设我们有一个具有以下功能的社交媒体平台：&lt;/p&gt;
&lt;p&gt;🔸用户管理
🔸内容创建与管理
🔸互动
🔸通知
🔸消息&lt;/p&gt;
&lt;p&gt;在单体架构中，上述所有业务功能都存在并作为一个单元部署。所有数据都存储在同一个数据库中。&lt;/p&gt;
&lt;p&gt;在微服务架构中，上述每个业务功能都被视为一个单元，拥有自己的数据库。API 网关将请求路由到服务，聚合响应等。一个集中管理服务处理负载均衡、故障恢复、配置等。&lt;/p&gt;
&lt;p&gt;单体架构的优点：&lt;/p&gt;
&lt;p&gt;✅ 简单性：作为一个单元开发、测试和部署应用程序更容易
✅ 性能：由于共享内存访问和没有网络延迟，可能会更快
✅ 统一过程：所有事情都在同一个地方和过程中发生 — 更容易的数据管理。&lt;/p&gt;
&lt;p&gt;单体架构的缺点：&lt;/p&gt;
&lt;p&gt;❌ 可伸缩性：灵活性有限，即使只有一个组件需要，也必须一起扩展。
❌ 部署风险：每次更改都需要进行整体部署。因为每个组件都相互连接，一个区域的错误可能会导致整个应用程序崩溃。
❌ 技术锁定：应用程序通常限制在一个技术栈中&lt;/p&gt;
&lt;p&gt;微服务架构的优点：&lt;/p&gt;
&lt;p&gt;✅ 独立部署：每个服务都可以独立部署、扩展、升级和重启
✅ 弹性：如果一个服务失败，其影响限于该服务及其消费者 — 减少爆炸半径
✅ 灵活性：为每个服务选择最佳技术栈&lt;/p&gt;
&lt;p&gt;微服务架构的缺点：&lt;/p&gt;
&lt;p&gt;❌ 复杂性：增加了诸如服务间通信、数据一致性等复杂性
❌ 数据管理：跨服务保持数据一致性可能具有挑战性
❌ 运营开销：监控、部署、日志记录等的复杂性增加&lt;/p&gt;
&lt;p&gt;那么你应该选择哪一个？&lt;/p&gt;
&lt;p&gt;单体架构最适合：&lt;/p&gt;
&lt;p&gt;🔹小规模应用程序
🔹需要简单部署和开发的应用程序
🔹需要组件间快速可靠通信的应用程序
🔹需要原子事务的应用程序&lt;/p&gt;
&lt;p&gt;微服务架构最适合：&lt;/p&gt;
&lt;p&gt;🔸大规模应用程序
🔸简化团队间开发和部署管理
🔸需要未来可伸缩性的应用程序
🔸需要故障隔离的应用程序&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/dd5179a49821043e23aa7211117a1ecf.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.atlassian.com/microservices/microservices-architecture/microservices-vs-monolith&quot;&gt;https://www.atlassian.com/microservices/microservices-architecture/microservices-vs-monolith&lt;/a&gt;
[2] &lt;a href=&quot;https://aws.amazon.com/compare/the-difference-between-monolithic-and-microservices-architecture/&quot;&gt;https://aws.amazon.com/compare/the-difference-between-monolithic-and-microservices-architecture/&lt;/a&gt;
[3] &lt;a href=&quot;https://www.geeksforgeeks.org/monolithic-vs-microservices-architecture/&quot;&gt;https://www.geeksforgeeks.org/monolithic-vs-microservices-architecture/&lt;/a&gt;
[4] &lt;a href=&quot;https://stackoverflow.com/questions/33041733/microservices-vs-monolithic-architecture&quot;&gt;https://stackoverflow.com/questions/33041733/microservices-vs-monolithic-architecture&lt;/a&gt;
[5] &lt;a href=&quot;https://www.reddit.com/r/dotnetcore/comments/12fbwau/microservices_vs_monolithic_architecture_which/?rdt=49560&quot;&gt;https://www.reddit.com/r/dotnetcore/comments/12fbwau/microservices_vs_monolithic_architecture_which/?rdt=49560&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>CORS是如何工作的？</title><link>https://blog.ithuo.net/posts/how-does-cors-work/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/how-does-cors-work/</guid><pubDate>Sun, 25 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;网络浏览器使用跨源资源共享（CORS）来管理对于提供网页的域名不同的其他域名的请求。这是一种浏览器安全机制，用于减轻跨站请求伪造和其他跨站攻击的风险。&lt;/p&gt;
&lt;p&gt;为了清晰地理解其工作原理，让我们分解一下 CORS 的工作流程：&lt;/p&gt;
&lt;h4&gt;1）网页发起请求&lt;/h4&gt;
&lt;p&gt;过程从一个网页（源 A）试图访问不同源（源 B）的资源开始。&lt;/p&gt;
&lt;h4&gt;2）“简单”或“非简单”请求检查&lt;/h4&gt;
&lt;p&gt;在发起实际请求之前，浏览器会检查请求是&quot;简单&quot;还是&quot;非简单&quot;。&quot;简单&quot;请求通常包括像 GET、POST 或 HEAD 这样的方法和一组有限的头部。如果请求是&quot;非简单&quot;的，浏览器会发起一个预检请求。&lt;/p&gt;
&lt;h4&gt;3）预检请求（针对非简单请求）&lt;/h4&gt;
&lt;p&gt;在浏览器完成了“非简单”请求检查之后，如果请求是“非简单”的，它将向目标源（源 B）发送一个 OPTIONS 请求。包含的头部将提供它想要进行的实际请求的详细信息。这些头部包括：&lt;/p&gt;
&lt;p&gt;🔸 Origin：调用脚本的源。
🔸 Access-Control-Request-Method：实际请求的 HTTP 方法。
🔸 Access-Control-Request-Headers：实际请求将发送的任何自定义头部。&lt;/p&gt;
&lt;h4&gt;4）服务器对预检请求的响应&lt;/h4&gt;
&lt;p&gt;一旦服务器（源 B）收到预检请求，它将发送一个响应。如果服务器决定源可以访问资源，它将用以下头部进行响应：&lt;/p&gt;
&lt;p&gt;🔹 Access-Control-Allow-Origin：指定哪些源被允许。这可以是一个特定的源，也可以是一个通配符 *。
🔹 Access-Control-Allow-Methods：指定哪些 HTTP 方法被允许。
🔹 Access-Control-Allow-Headers：指定可以使用哪些 HTTP 头部。&lt;/p&gt;
&lt;p&gt;如果服务器没有提供正确的头部，或者这些头部与请求本身的详细信息不匹配，浏览器将拒绝实际请求。&lt;/p&gt;
&lt;h4&gt;5）发送实际请求&lt;/h4&gt;
&lt;p&gt;现在预检请求已经处理完毕（成功或不需要），浏览器可以向源 B 发送实际请求。请求将包括任何必要的头部、凭证或数据。&lt;/p&gt;
&lt;p&gt;6#### ）服务器对实际请求的响应
一旦服务器（源 B）收到请求，它会处理并发送响应。与响应一起，服务器仍然会发送适当的 CORS 相关头部。&lt;/p&gt;
&lt;h4&gt;7）浏览器执行&lt;/h4&gt;
&lt;p&gt;最后但同样重要的是，浏览器会最后一次检查响应中的 CORS 头部。如果一切检查都通过，那么浏览器会将响应提供给网页的 JavaScript。如果没有，那么浏览器将阻止对响应的访问，并在控制台中记录一个 CORS 错误。&lt;/p&gt;
&lt;p&gt;CORS 确保服务器可以控制谁可以访问他们的资源。浏览器执行这些规则以保护用户免受潜在的安全威胁。虽然 CORS 引入了一个额外的复杂性层，但它提供了一个有效的安全措施，以确保安全的跨源数据共享。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/d91106f1a493da16abb761b7c10f8289.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://zh.wikipedia.org/zh-cn/%E8%B7%A8%E4%BE%86%E6%BA%90%E8%B3%87%E6%BA%90%E5%85%B1%E4%BA%AB&quot;&gt;https://zh.wikipedia.org/zh-cn/跨來源資源共享&lt;/a&gt;
[2] &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS&lt;/a&gt;
[3] &lt;a href=&quot;https://aws.amazon.com/what-is/cross-origin-resource-sharing/&quot;&gt;https://aws.amazon.com/what-is/cross-origin-resource-sharing/&lt;/a&gt;
[4] &lt;a href=&quot;https://en.wikipedia.org/wiki/Cross-origin_resource_sharing&quot;&gt;https://en.wikipedia.org/wiki/Cross-origin_resource_sharing&lt;/a&gt;
[5] &lt;a href=&quot;https://portswigger.net/web-security/cors&quot;&gt;https://portswigger.net/web-security/cors&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Linux权限是如何工作的？</title><link>https://blog.ithuo.net/posts/how-does-linux-permissions-work/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/how-does-linux-permissions-work/</guid><pubDate>Tue, 13 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Linux是一个多用户操作系统，内置了强大的用户和组权限。这些权限提供了限制谁可以访问文件或目录以及他们可以执行的操作（读取，写入或执行）的能力。&lt;/p&gt;
&lt;p&gt;每个文件和目录都有三种权限类型：&lt;/p&gt;
&lt;p&gt;🔸 读取（r）：允许读取文件或列出目录的内容。
🔸 写入（w）：允许你修改文件的内容或在目录中创建或删除文件。
🔸 执行（x）：允许文件作为程序运行，或者进入目录。&lt;/p&gt;
&lt;p&gt;权限被分配给三种类型的用户：&lt;/p&gt;
&lt;p&gt;🔸 用户（u）：文件或目录的所有者。
🔸 组（g）：是文件组成员的其他用户。
🔸 其他（o）：不是所有者或组成员的所有其他用户。&lt;/p&gt;
&lt;p&gt;要查看权限，你可以使用 &lt;code&gt;ls -l&lt;/code&gt; 命令，它会显示一个由10个字符组成的字符串。第一个字符表示文件类型；d 表示目录，- 表示常规文件。然后是三组 r，w，x，或者如果该权限未被授予，则为 -。每组分别代表用户，组和其他（按顺序）。&lt;/p&gt;
&lt;p&gt;变更文件或目录的权限可以使用 &lt;code&gt;chmod&lt;/code&gt; 命令（更改模式）进行更改。可以使用符号模式（u/g/o/a +/- r/w/x）或数字模式（八进制表示：读取=4，写入=2，执行=1）来更改权限。&lt;/p&gt;
&lt;p&gt;示例：&lt;code&gt;chmod u+w file&lt;/code&gt; 为用户添加写入权限，&lt;code&gt;chmod 744 file&lt;/code&gt; 为用户设置读取，写入和执行权限，为组和其他设置读取权限。&lt;/p&gt;
&lt;p&gt;文件和目录的所有权也可以使用 &lt;code&gt;chown&lt;/code&gt; 和 &lt;code&gt;chgrp&lt;/code&gt; 命令进行更改。&lt;/p&gt;
&lt;p&gt;理解 Linux 权限在软件开发的多个方面都是关键，从管理系统安全性到部署和操作。在处理权限时要牢记的一个关键原则是，通常最好从更严格的权限开始，然后根据需要逐渐添加更多权限。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/82344e5e972e48177830b6139a8ade92.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://linuxize.com/post/understanding-linux-file-permissions/&quot;&gt;https://linuxize.com/post/understanding-linux-file-permissions/&lt;/a&gt;
[2] &lt;a href=&quot;https://www.geeksforgeeks.org/permissions-in-linux/&quot;&gt;https://www.geeksforgeeks.org/permissions-in-linux/&lt;/a&gt;
[3] &lt;a href=&quot;https://www.guru99.com/file-permissions.html&quot;&gt;https://www.guru99.com/file-permissions.html&lt;/a&gt;
[4] &lt;a href=&quot;https://www.linuxfoundation.org/blog/blog/classic-sysadmin-understanding-linux-file-permissions&quot;&gt;https://www.linuxfoundation.org/blog/blog/classic-sysadmin-understanding-linux-file-permissions&lt;/a&gt;
[5] &lt;a href=&quot;https://www.redhat.com/sysadmin/linux-file-permissions-explained&quot;&gt;https://www.redhat.com/sysadmin/linux-file-permissions-explained&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>如何使用缓存</title><link>https://blog.ithuo.net/posts/how-to-use-cache/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/how-to-use-cache/</guid><pubDate>Mon, 12 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;开发人员至少对缓存的概念有些熟悉。毕竟，这种技术现在是如此普遍，从CPU到浏览器缓存，所有软件都在一定程度上依赖于缓存技术来提供快速响应。仅仅几毫秒的延迟就可能导致数百万的收入损失，因此亚毫秒级的响应正在成为常态。市场上有大量的缓存解决方案，因此选择正确的解决方案的过程本身就是一次冒险。&lt;/p&gt;
&lt;p&gt;在这篇文章中，我们将讨论什么是缓存，以及缓存的好处。接下来，我们将讨论不同的缓存策略和缓存回收策略。最后，我们将回顾一些现有的可用缓存解决方案。&lt;/p&gt;
&lt;h2&gt;缓存基础知识&lt;/h2&gt;
&lt;h3&gt;什么是缓存？&lt;/h3&gt;
&lt;p&gt;在软件开发中，缓存是一个组件，用于存储数据集的部分，这些数据集要么需要很长时间才能计算，要么来自另一个底层系统。通过减少不必要的计算并防止频繁使用数据的额外请求往返，可以提高应用程序性能或减少响应延迟。&lt;/p&gt;
&lt;p&gt;缓存被设计为近实时地响应缓存请求，因此被实现为简单的键值存储。然而，内部工作方式仍然可以非常不同，并且取决于后端存储。&lt;/p&gt;
&lt;p&gt;典型的用例是用于数据库的内存缓存或可缓慢检索的基于磁盘的数据，远程存储在慢速网络连接后面的数据或先前计算的结果。&lt;/p&gt;
&lt;h3&gt;什么是缓存命中和缓存未命中？&lt;/h3&gt;
&lt;p&gt;当请求的数据在该高速缓存中已经可用并且可以在没有任何其他操作或处理的情况下返回时，发生缓存命中。&lt;/p&gt;
&lt;p&gt;当请求的数据尚不可用，并且必须从底层系统检索数据或在返回数据之前计算数据时，就会发生缓存未命中。&lt;/p&gt;
&lt;h2&gt;应用程序挑战和缓存优势&lt;/h2&gt;
&lt;p&gt;现代系统必须适应大量的流量，并需要快速响应。此外，随着流量和数据量的增加，应用程序需要能够增长才能成功。另一方面，大多数基础设施直接或间接地依赖于基于磁盘的数据库。&lt;/p&gt;
&lt;p&gt;对于需要低延迟和可伸缩性的分布式应用程序来说，基于XML的数据库可能会带来很多挑战。一些最常见的挑战包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;缓慢的查询处理：从磁盘检索数据的速度，加上增加的查询处理时间，通常会使响应时间相对较高。有很多优化技术和设计可以提高查询性能。然而，在达到介质的物理限制之前，我们可以实现的性能是有限的。毕竟，数据库查询的大部分延迟是由从磁盘检索数据的物理过程决定的。&lt;/li&gt;
&lt;li&gt;可伸缩性成本：数据库可以水平或垂直扩展。这两种缩放技术都有其缺点。垂直扩展既昂贵，又可能达到可添加到机器的组件的物理限制。水平扩展允许对数据库进行分片以实现更高的吞吐量。尽管如此，扩展到更高的读取可能是昂贵的，并且可能需要大量的副本来实现。此外，我们必须非常小心，不要在试图实现更高的响应时间时变得不平衡。&lt;/li&gt;
&lt;li&gt;可用性：有时，与数据库服务器或数据库分片的连接可能会中断。如果没有缓存，系统将变得无响应，直到连接恢复。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;缓存的总体好处是帮助内容消费者和内容提供者。一个好的缓存策略可以提供几个优点。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提高响应速度：缓存可以提供更快的内容检索，并防止额外的网络往返。在用户附近维护的缓存（如浏览器缓存）可以使这种检索几乎是即时的。&lt;/li&gt;
&lt;li&gt;在相同的硬件上提高性能：对于内容起源的服务器，可以从相同的硬件中挤出积极的缓存。内容所有者可以利用更强大的服务器沿着传递路径来承担内容加载的主要任务。&lt;/li&gt;
&lt;li&gt;降低网络成本：根据缓存策略，内容可以在网络路径的多个区域中可用。这样，内容可以移动到更靠近用户的位置，并减少该高速缓存之外的网络活动。&lt;/li&gt;
&lt;li&gt;内容交付的稳健性：通过某些策略，即使由于网络短缺或服务器故障而无法使用缓存，也可以使用缓存向最终用户提供内容。&lt;/li&gt;
&lt;li&gt;消除数据库热点：在许多应用程序中，一小部分数据可能比其他数据更频繁地被访问。这可能会导致数据库中出现热点。热点可能需要基于最频繁使用的数据的吞吐量要求来过度供应数据库资源。在内存缓存中存储公共密钥可以减少过度配置的需求，同时提供快速和可预测的性能。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;缓存什么数据&lt;/h3&gt;
&lt;p&gt;一个很好的缓存指示器是找到任何元素，其中某个请求的多次执行将导致相同的结果。这包括数据库查询、HTML片段或繁重计算的输出。&lt;/p&gt;
&lt;p&gt;一般来说，只有一个规则适用。数据不应该经常更改，但应该经常读取。&lt;/p&gt;
&lt;h3&gt;什么数据不应缓存&lt;/h3&gt;
&lt;p&gt;易失性数据通常不适合缓存。每当数据发生变化时，必须使该高速缓存无效，并且根据我们使用的缓存策略，这可能是一个代价高昂的操作。&lt;/p&gt;
&lt;p&gt;另一种不能从缓存中受益的数据类型是检索速度快的数据。缓存这些元素将在填充该高速缓存时引入额外的往返，并不可避免地增加所需的内存。缓存这些元素的好处可能不会显示预期的结果，从而使它们不值得开销。&lt;/p&gt;
&lt;h2&gt;缓存类型&lt;/h2&gt;
&lt;h3&gt;内存缓存&lt;/h3&gt;
&lt;p&gt;内存中缓存是一块RAM，用于临时存储数据。由于访问RAM比访问其他介质（如硬盘驱动器或网络）要快得多，因此缓存可以帮助应用程序更快地运行，因为它可以更快地访问数据。&lt;/p&gt;
&lt;p&gt;内存缓存的工作原理是首先留出一部分RAM用作该高速缓存。当应用程序尝试读取数据时，通常是从数据库等数据存储系统中读取数据，它会检查所需的记录是否已存在于该高速缓存中。如果是，那么应用程序将从该高速缓存读取数据，从而消除对数据库的较慢访问。如果所需的记录不在该高速缓存中，则应用程序从源读取该记录。当它检索该数据时，它还将数据写入该高速缓存，以便将来应用程序需要相同的数据时，它可以快速地从该高速缓存中获取数据。&lt;/p&gt;
&lt;p&gt;内存缓存的一个广泛的用例是加速数据库应用程序，特别是那些执行许多数据库读取的应用程序。通过用从该高速缓存读取数据来替换一部分数据库读取，应用程序可以消除由于频繁的数据库往返而引起的延迟。这种用例通常出现在大量数据访问的环境中，例如在具有数据库动态内容的高流量网站中。&lt;/p&gt;
&lt;p&gt;另一个用例涉及查询加速，其中对数据库的复杂查询的结果存储在该高速缓存中。运行分组和排序等操作的复杂查询可能需要大量时间才能完成。如果查询重复运行，就像许多用户访问的商业智能（BI）仪表板中的情况一样，将结果存储在缓存中将使这些仪表板具有更高的响应能力。&lt;/p&gt;
&lt;h3&gt;分布式缓存&lt;/h3&gt;
&lt;p&gt;分布式缓存是一种系统，它将多台联网计算机的RAM集中到一个内存数据存储中，用作缓存，以提供对数据的快速访问。&lt;/p&gt;
&lt;p&gt;虽然大多数缓存传统上存在于一个物理组件中，无论是服务器还是硬件组件，但分布式缓存可以通过链接多台计算机来获得更大的容量和处理能力，从而超越单个机器的物理限制。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/92d6376d73eeb8961f51481289cef64c.png&quot; alt=&quot;8fee8oqs32mtpi8ihqdo.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;分布式缓存将多台计算机的RAM池化到单个内存中的数据存储中，用作数据缓存以提供对数据的快速访问。&lt;/p&gt;
&lt;p&gt;分布式缓存在具有高数据量和负载的环境中特别有用。分布式体系结构允许通过向群集添加更多硬件来实现增量扩展，从而使该高速缓存能够随着数据增长而同步增长。&lt;/p&gt;
&lt;p&gt;有几种应用程序可以将分布式缓存作为其架构的一部分的用例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;应用加速：大多数应用程序都直接或间接地依赖于基于磁盘的数据库，因此无法始终满足当今日益苛刻的要求。通过在分布式缓存中缓存最频繁访问的数据，我们可以显著减少基于磁盘的系统的瓶颈。&lt;/li&gt;
&lt;li&gt;存储会话数据：站点可以将用户会话数据存储在缓存中，作为多个操作的输入，例如购物车和推荐。使用分布式缓存，我们可以拥有大量并发的Web会话，这些会话可以被系统中的任何服务器访问。这使我们能够将Web流量负载平衡到多个服务器，并且在任何应用服务器出现故障时不会丢失会话。&lt;/li&gt;
&lt;li&gt;极高的可扩展性：某些应用程序需要大量数据。通过在多台机器上利用更多资源，分布式缓存可以响应这些请求。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;缓存数据访问策略&lt;/h2&gt;
&lt;p&gt;当我们缓存数据时，我们可以从各种各样的缓存策略中进行选择，包括主动和被动的方法。我们选择实现的模式应该与我们的缓存和应用程序目标直接相关。&lt;/p&gt;
&lt;h3&gt;缓存（延迟加载）&lt;/h3&gt;
&lt;p&gt;缓存可能是最常用的缓存方法。此策略规定该高速缓存必须位于旁边，应用程序将直接与该高速缓存和数据库通信。&lt;/p&gt;
&lt;p&gt;在此策略中，当应用程序需要某些数据时，它将首先查询该高速缓存。如果该高速缓存包含该元素，则我们有一个高速缓存命中，并且该高速缓存将数据返回给应用程序。如果数据不存在于该高速缓存中，则表示缓存未命中。应用程序现在必须做一些额外的工作。应用程序首先必须在数据库中查询所需的数据。然后，它将数据返回给客户端，最后用检索到的数据更新该高速缓存。现在，对同一数据的任何后续读取都将导致缓存命中。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/3100eb9a733448d662112a16b8d4e4fa.png&quot; alt=&quot;br60vgp346e9n9uru903.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;缓存旁缓存通常是通用的，最适合读取繁重的工作负载。&lt;/p&gt;
&lt;p&gt;使用缓存的系统对缓存故障具有弹性。如果有多个缓存节点，并且一个节点发生故障，它不会导致连接的全部原因，但应用程序可能会面临增加的延迟。随着新的缓存节点上线，更多的请求被重定向到它们，节点将在每次缓存未命中时填充所需的数据。在整个缓存失败的情况下，应用程序仍然可以通过数据库请求访问数据。&lt;/p&gt;
&lt;p&gt;这种策略的缺点是在缓存未命中之后需要三次网络往返。首先，应用程序需要检查该高速缓存。接下来，应用程序需要从数据库中检索数据。最后，应用程序需要更新该高速缓存。这些往返可能会导致响应的明显延迟。&lt;/p&gt;
&lt;h3&gt;Read Through&lt;/h3&gt;
&lt;p&gt;与Cache Aside相比，Read Through将获取值的责任从Cache转移到该高速缓存提供程序。此策略要求该高速缓存必须位于应用程序和数据库之间。&lt;/p&gt;
&lt;p&gt;在此策略中，当应用程序需要某些数据时，它将查询该高速缓存。如果该高速缓存包含该元素，则我们有一个高速缓存命中，并且该高速缓存将数据返回给应用程序。如果数据不存在于该高速缓存中，则表示缓存未命中。该高速缓存首先必须查询数据库以获得所需的数据。之后，该高速缓存将用所需数据更新自身。最后，该高速缓存将检索到的数据返回给应用程序。现在对同一数据的任何后续读取都将导致缓存命中。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/7e57e3115cdc35842c25df5df80236ca.png&quot; alt=&quot;i77mkvey94qmqebjgb2g.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;当我们有数据要保存在该高速缓存中以供频繁读取时，即使这些数据定期更改，读通缓存也是与写通策略配合使用的理想选择。&lt;/p&gt;
&lt;p&gt;此策略不适用于应用程序中的所有数据访问。如果系统将该高速缓存用于数据库和应用程序之间的所有数据访问，则缓存故障可能导致应用程序性能瓶颈，或者由于应用程序无法访问数据库而直接导致应用程序崩溃。&lt;/p&gt;
&lt;h3&gt;写入&lt;/h3&gt;
&lt;p&gt;与Read Through类似，但对于写入，Write Through将写入责任转移到该高速缓存提供程序。此策略要求该高速缓存必须位于应用程序和数据库之间。此策略不提供任何从主数据源阅读数据的功能，但处理应用程序发出新数据或更新时发生的情况。&lt;/p&gt;
&lt;p&gt;在此策略中，当应用程序尝试更新现有数据或向缓存中添加新数据时，它将命中该高速缓存。此操作总是导致缓存命中，并且该高速缓存将更新其条目或为数据创建新条目。然后，该高速缓存将更新主数据存储。最后，该高速缓存将确认数据已成功存储。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/e67b32c50a516482db07ce22ec5835ce.png&quot; alt=&quot;55dsim7gs0yewzq06jo2.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;就其本身而言，Write Through似乎做得不多，如果事实上，它引入了额外的写入延迟，因为数据首先写入ache，然后写入数据库。但是，当此策略与Read Through阅读策略配对时，可确保数据一致性。&lt;/p&gt;
&lt;p&gt;与Read Through策略一样，此策略不适用于应用程序中的所有数据访问。如果系统将该高速缓存用于数据库和应用程序之间的所有数据访问，则缓存故障可能导致应用程序性能瓶颈，或者由于应用程序无法访问数据库而直接导致应用程序崩溃。&lt;/p&gt;
&lt;h3&gt;Write Around&lt;/h3&gt;
&lt;p&gt;写回缓存具有与直写缓存类似的功能。在写回缓存该高速缓存数据将被更新，只有当它已经映射到该高速缓存，并同时写入数据“通过”到后端存储。&lt;/p&gt;
&lt;p&gt;在此策略中，当应用程序尝试添加或更新某些数据时，它将查询该高速缓存。该高速缓存将用更新的数据更新后端存储。然后，如果该高速缓存包含更新数据的条目，则它将更新自身，否则，它将完全跳过数据。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/789bf947c16e56b2bf6d2ad012ea20bb.png&quot; alt=&quot;mg31m8uyogqd951m6wyv.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;此策略保护该高速缓存不被不那么频繁读取的数据淹没，同时为写入操作引入最小延迟。它还确保了该高速缓存和主数据存储之间的数据一致性。因此，它非常适合具有非常高的一次性数据写入量的系统，例如来自聊天应用程序的消息。&lt;/p&gt;
&lt;p&gt;这种策略的缺点是，最近写入的数据总是会导致缓存未命中（因此延迟更高），因为数据只能在较慢的后端存储中找到。&lt;/p&gt;
&lt;h3&gt;Write Back&lt;/h3&gt;
&lt;p&gt;回写的工作原理与直写策略非常相似。主要区别在于，该高速缓存不同步更新主数据存储，而是在预定义的时间间隔后分批更新。&lt;/p&gt;
&lt;p&gt;在此策略中，当应用程序添加或更新数据时，它会与案例进行通信。案例将向应用程序发送确认。在定义的时间间隔之后，该高速缓存将对数据存储执行批量查询并更新所有相关数据。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/dc0556072e76531f745bbc4f0864d004.png&quot; alt=&quot;3vsci7om1cdx3bd4oh7s.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;回写缓存提高了写入性能，是读取和写入繁重工作负载的理想选择。&lt;/p&gt;
&lt;p&gt;由于应用程序只写入缓存服务，因此它不需要等待数据写入基础数据源，从而提高了性能。此外，由于所有的阅读和写都是在该高速缓存上执行的，因此应用程序不会出现数据库故障。如果数据库失败，仍可以访问排队的项目。&lt;/p&gt;
&lt;p&gt;这一战略也带来了一些需要解决的问题。考虑到该策略首先读取和写入该高速缓存，在该高速缓存和主数据存储之间仅存在最终一致性。如果主数据存储与其他应用程序共享，则如果其他应用程序的读取操作发生在批处理操作之间，则它们总是有获得陈旧数据的危险。此外，无法知道缓存更新是否会与其他外部更新冲突。这必须手动或手动地处理。&lt;/p&gt;
&lt;h2&gt;Eviction Policies&lt;/h2&gt;
&lt;p&gt;回收策略允许该高速缓存确保其大小不超过最大限制。为了实现这一点，根据驱逐策略从缓存中删除现有元素，但可以根据应用程序的要求进行自定义。&lt;/p&gt;
&lt;p&gt;缓存解决方案可能与不同的回收策略兼容，但在选择缓存策略之前，最好了解应用程序可能需要什么回收策略。&lt;/p&gt;
&lt;h3&gt;Least Recently Used (LRU)&lt;/h3&gt;
&lt;p&gt;最常用的策略之一是最近最少使用。Least Recently Used eviction（最近最少使用的清除）策略会删除在时间上最早使用的值。为了进行分析，该高速缓存中的每个记录都跟踪其最后一次访问时间戳，该时间戳可以与其他记录进行比较，以找到最近最少使用的项。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/520604cdd964bb3a2bc5a4f2d2deadbd.png&quot; alt=&quot;secea16e7ey625tecmeu.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Least Frequently Used (LFU)&lt;/h3&gt;
&lt;p&gt;最不常用驱逐策略会删除访问次数最少的值。为了进行分析，每个记录使用仅递增的计数器来跟踪其访问。然后可以将该计数器与其他记录的计数器进行比较，以找到最不常用的元素。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/4aeb149565ddb52d7f74d3a69bc700d8.png&quot; alt=&quot;yh0cfk9kud0bt9l4j56z.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Most Recently Used (MRU)&lt;/h3&gt;
&lt;p&gt;Most Recently Used eviction（最近使用的回收）策略将删除在时间上最近使用的值。为了进行分析，每个记录都会跟踪其最后一次访问的时间戳，可以将其与其他记录进行比较，以找到最近使用的元素。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/520604cdd964bb3a2bc5a4f2d2deadbd.png&quot; alt=&quot;secea16e7ey625tecmeu.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Most Frequently Used (MFU)&lt;/h3&gt;
&lt;p&gt;最频繁使用的驱逐策略删除访问次数最多的值。为了进行分析，每个记录使用仅递增的计数器来跟踪其访问。然后，可以将此计数器与这些记录进行比较，以查找最常用的元素。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/4aeb149565ddb52d7f74d3a69bc700d8.png&quot; alt=&quot;yh0cfk9kud0bt9l4j56z.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Least Time To Live (LTTL)&lt;/h3&gt;
&lt;p&gt;最短生存时间驱逐策略删除TTL字段中时间最短的值。要进行此分析，每个记录都要跟踪其TTL，该TTL是在将其添加到该高速缓存时分配的，并以特定的时间间隔递减。然后可以将该字段与其他记录的字段进行比较，以找到在该高速缓存中生存时间最长的项。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/d8fbb29849bbb3043e64e7e431f13389.png&quot; alt=&quot;ygguyemtr83z07zby3bc.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Random&lt;/h3&gt;
&lt;p&gt;Random eviction策略随机删除值。此策略不考虑项在该高速缓存中的插入顺序，也不考虑访问项的频率。当我们有循环访问并且所有元素都被连续扫描时，或者我们期望分布是均匀的时，可以使用此策略。&lt;/p&gt;
&lt;h2&gt;缓存中间件&lt;/h2&gt;
&lt;h3&gt;Memcached&lt;/h3&gt;
&lt;p&gt;Memcached是一个通用的分布式内存缓存系统。它通常用于动态数据库驱动的网站，以减少必须读取外部数据源的次数。Memcached是免费和开源的，在修订的BSD许可证下授权，使其成为一个非常低成本的解决方案。&lt;/p&gt;
&lt;p&gt;该系统被设计为一个简单的键值存储。Memcached不理解应用程序正在保存什么-它可以将字符串和对象存储为值，而键必须始终存储为字符串。&lt;/p&gt;
&lt;p&gt;在分布式环境中，Memcached节点不会相互交互，因为系统不提供任何同步或复制功能。因此，客户端必须决定哪个节点必须访问特定的数据集。值得注意的Memcached用户包括YouTube，Reddit，Twitter和维基百科。&lt;/p&gt;
&lt;h3&gt;Limitations&lt;/h3&gt;
&lt;p&gt;Memcached不为该高速缓存条目提供任何持久性，因此每次崩溃或重新启动时，该高速缓存都需要再次预热。&lt;/p&gt;
&lt;p&gt;另一个限制是值的大小限制。每个键的值必须最多为1 MB。这意味着大型对象或数据集可能会占用更多空间，并且必须在不同的缓存插槽中进行分段。此外，对象在存储到该高速缓存中之前必须被序列化，从而增加了阅读/写操作的延迟。&lt;/p&gt;
&lt;h3&gt;Redis&lt;/h3&gt;
&lt;p&gt;Redis（Remote Dictionary Server）是一个内存数据结构存储，用作分布式内存键值数据库，缓存和消息代理。&lt;/p&gt;
&lt;p&gt;Redis支持多种数据结构，即列表，集合，排序集合和字符串。它还支持范围查询、超级日志和地理空间索引。&lt;/p&gt;
&lt;p&gt;Redis通常将整个数据集保存在内存中，但可以配置为通过两种不同的方法持久化其数据。第一种方法是通过快照，其中数据集以二进制转储的形式定期从内存异步传输到磁盘。第二种方法是日志记录，其中将修改数据集的每个操作的记录添加到后台进程中的仅追加文件中。&lt;/p&gt;
&lt;p&gt;默认情况下，Redis至少每2秒向文件系统写入一次数据，如果需要，可以提供或多或少的健壮选项。在默认设置下发生系统故障的情况下，只有几秒钟的数据会丢失。&lt;/p&gt;
&lt;p&gt;Redis还支持主副本复制。来自任何Redis服务器的数据都可以复制到任意数量的副本。Redis还提供了一个订阅的特性，所以一个副本的客户端可以订阅一个频道，并接收发布给主服务器的完整消息。&lt;/p&gt;
&lt;h3&gt;Limitations&lt;/h3&gt;
&lt;p&gt;在分布式环境中，Redis根据分配给每个master的hash slot对数据进行分片。如果任何主机出现故障，将在此插槽上写入的数据将丢失。此外，不支持故障转移，除非主设备至少有一个从设备。&lt;/p&gt;
&lt;p&gt;由于Redis将数据存储在内存中的大型哈希表中，因此需要大量的RAM。&lt;/p&gt;
&lt;h3&gt;Aerospike&lt;/h3&gt;
&lt;p&gt;Aerospike是一个闪存和内存中的开源分布式键值NoSQL数据库管理系统。Aerospike最重要的卖点之一是支持混合内存模型-这意味着如果RAM用完，其他合适的闪存驱动器（如SSD，NVMes等）可以用作替代品。&lt;/p&gt;
&lt;p&gt;Aerospike使用闪存驱动器进行垂直扩展。IOPS（每秒输入输出）持续增长。SSD可以在每个节点上存储比DRAM多几个数量级的数据，NVMe驱动器现在可以在每个驱动器上执行高达100 K的IOPS。Aerospike利用了这些功能，它可以在亚毫秒级的延迟下每秒执行数百万次操作。&lt;/p&gt;
&lt;h3&gt;Hazelcast&lt;/h3&gt;
&lt;p&gt;Hazelcast是一个基于Java的开源内存数据网格。在Hazelcast网格中，数据均匀地分布在集群的节点之间，允许处理和可用存储的水平扩展。备份也分布在节点之间，以防止故障或任何单个节点。&lt;/p&gt;
&lt;p&gt;Hazelcast可以在本地、云端和Docker容器中运行。Hazelcast提供多种云配置和部署技术的集成，包括Apache jclouds、Consul、eruaka、Kubernetes和Zookeeper。Hazelcast还可以使基于云的节点或本地节点能够自动发现彼此。&lt;/p&gt;
&lt;h2&gt;最后的想法&lt;/h2&gt;
&lt;p&gt;在这篇文章中，我们讨论了什么是缓存以及缓存的好处。我们还研究了什么是内存缓存和分布式缓存。我们回顾了最常见的缓存策略，并讨论了最流行的驱逐策略。最后我们回顾了一些可用的缓存提供程序。&lt;/p&gt;
&lt;p&gt;现在应该更加清楚的是，选择缓存服务不仅是在知名度或熟悉度之间做出决定，而且更多的是应用程序的用例，数据访问模式，基础设施要求，可用性和数据量等。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>数据库索引是如何工作的？</title><link>https://blog.ithuo.net/posts/how-does-database-index-work/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/how-does-database-index-work/</guid><pubDate>Sat, 10 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;ul&gt;
&lt;li&gt;大多数数据库都需要某种形式的索引来满足性能基准。当数据正确地被索引时，搜索数据库就会变得更简单，这也提高了系统的整体性能。&lt;/li&gt;
&lt;li&gt;数据库索引就像书的索引一样。它可以节省你的时间和精力，让你能够轻松地找到你要找的内容，而不必翻阅每一页。数据库索引也是这样工作的。索引是一个键值对，其中键用于搜索数据，而不是相应的索引列，值则是指向表中相关行的指针。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/a2b1e00761f39d34924c5ba2f7d579ac.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;为了充分利用你的数据库，你应该根据任务选择正确的索引类型。&lt;/li&gt;
&lt;li&gt;最常用的索引结构之一是B树，其中键被排序并组织在一个层次化的树结构中。在搜索数据时，树会遍历到包含适当键和指向表中相关行的指针的叶节点。B树之所以常用，是因为它在存储和搜索有序数据方面的效率。它们的平衡结构意味着所有的键都可以在相同的步骤数内被访问，使得性能保持一致。&lt;/li&gt;
&lt;li&gt;哈希索引最适合在你搜索精确值匹配时使用。哈希索引的关键组成部分是哈希函数。在搜索特定值时，搜索值会通过哈希函数，返回一个哈希值。这个哈希值告诉数据库键和指针在哈希表中的位置。&lt;/li&gt;
&lt;li&gt;对于具有低唯一值集的列，可以使用位图索引。在位图索引中，每个位图代表一个唯一值。位图使用1和0来表示数据集中值的存在或缺失。对于存在的值，位图中1的位置显示了表中行的位置。位图索引在处理多列被使用的复杂查询时非常有效。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/e5646c2b280baa880b66506f8d8279fa.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当你在对表进行索引时，一定要根据WHERE子句中最常用的列仔细选择要索引的列。当多个列经常在WHERE子句中一起使用时，可以使用复合索引。在复合索引中，两个或更多列的组合被用来创建一个连接键。然后，根据索引策略，例如上述选项，存储键。&lt;/li&gt;
&lt;li&gt;索引可以是一把双刃剑。它显著加快了查询速度，但也占用了存储空间，并增加了操作的开销。平衡性能和最优存储是至关重要的，以充分利用你的数据库而不引入低效率。&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Derick</author></item><item><title>5种缓存策略介绍</title><link>https://blog.ithuo.net/posts/introduction-to-5-cache-strategies/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/introduction-to-5-cache-strategies/</guid><pubDate>Thu, 08 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在当今互联网世界中，性能是任何开发团队需要重点考虑的因素。缓存是提升性能的最常用技术之一，因为它简单且适用范围广。&lt;/p&gt;
&lt;p&gt;通过缓存，数据被复制并存储在易于访问的位置，如浏览器或CDN。&lt;/p&gt;
&lt;p&gt;如何更新和清除数据是任何缓存策略设计的关键组成部分。有许多技术可供选择，每种技术都有其独特的适用场景。&lt;/p&gt;
&lt;h4&gt;五种缓存策略&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;最近最少使用（LRU）是一种缓存管理方法，通过移除最长时间未被访问或使用的数据来为新数据腾出空间。它假设最近访问的数据将很快再次被需要。这是一种非常常见的方法，经常用于浏览器、CDN和操作系统。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/24244c5249cf343c01478a7ca065101e.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;最近最常使用（MRU）是LRU的反面，其中最先移除的是最近使用的数据。这种方法更常用于流处理或批处理平台，因为一旦数据被使用，就不太可能再次需要。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/6cb3e7f7a1091d7d137c6ac2602f0782.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;最不常使用（LFU）移除最少使用的数据。尽管它比LRU更准确，但它需要一个机制来记录数据被访问的频率，这增加了复杂性。LFU还有保留过时数据在缓存中的风险。因此，它通常与其他策略（如LRU）结合使用。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/21c96725f04eee671c87d6e6ecceb307.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用生存时间（TTL），数据在缓存中保留一段预定义的时间。这对于数据的当前状态只在一定时间内有效的情况（如会话数据）是理想的。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/ce876539f12fc0f1b47b3f7b35fa35b8.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;双层缓存提供了一种更复杂的方法，它在速度和成本之间找到了平衡。在这种设计中，数据被分为第一层和第二层。第一层是一个更小、更快、通常更昂贵的缓存层，存储频繁使用的数据。第二层是一个更大、更慢、更便宜的层，存储较少使用的数据。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/106e2212d475673a41aa7fd938f09d58.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;上述五种策略是最流行的缓存方法。还有其他值得一提的方法，如：&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;先进先出（FIFO）：最早的数据首先被删除。&lt;/li&gt;
&lt;li&gt;随机替换（RR）：随机选择要删除的数据。&lt;/li&gt;
&lt;li&gt;自适应替换缓存（ARC）：使用自调整算法，跟踪最近性和频率来确定首先删除哪些数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最佳的缓存策略取决于系统的特定需求和约束。理解并适当地利用可用的不同缓存策略可以显著提高应用程序的性能。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>什么是OAuth2.0</title><link>https://blog.ithuo.net/posts/what-is-oauth2-0/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/what-is-oauth2-0/</guid><pubDate>Wed, 07 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;OAuth 2.0 是一个授权框架，它使应用程序能够在不共享用户密码的情况下访问用户在另一个服务（如 Facebook 或 GitHub）上的数据。它本质上是应用程序、服务和用户之间的一种数字握手，每个人都同意共享什么。&lt;/p&gt;
&lt;p&gt;OAuth 2.0是如何工作的。&lt;/p&gt;
&lt;p&gt;这个过程通常包括 6 个步骤，涉及 4 个组件：&lt;/p&gt;
&lt;p&gt;🔸 客户端（想要访问的应用程序）
🔸 资源所有者（用户）
🔸 授权服务器
🔸 资源服务器&lt;/p&gt;
&lt;p&gt;为了理解这个过程，让我们看看一个游戏如何连接到玩家的 Facebook 账户。&lt;/p&gt;
&lt;p&gt;𝗦𝘁𝗲𝗽 𝟭) 请求访问：
在游戏（客户端）中，玩家（用户）点击“连接 Facebook”按钮，以链接他们的个人资料并找到朋友。&lt;/p&gt;
&lt;p&gt;𝗦𝘁𝗲𝗽 𝟮) 重定向到服务：
游戏将玩家重定向到 Facebook（服务）的登录页面。&lt;/p&gt;
&lt;p&gt;𝗦𝘁𝗲𝗽 𝟯) 请求权限：
登录后，游戏请求访问的数据将显示给玩家，他们可以选择允许或拒绝。&lt;/p&gt;
&lt;p&gt;𝗦𝘁𝗲𝗽 𝟰) 授权码：
如果玩家给予了他们的批准，Facebook 将玩家与授权码（来自授权服务器）一起重定向回游戏。该代码是一个临时凭证，证明了玩家的同意。&lt;/p&gt;
&lt;p&gt;𝗦𝘁𝗲𝗽 𝟱) 交换代码以获取令牌：
游戏现在将授权码以及其自身的身份信息在后台发送到 Facebook 的服务器。Facebook 识别授权码和游戏的身份，并返回一个访问令牌。&lt;/p&gt;
&lt;p&gt;𝗦𝘁𝗲𝗽 𝟲) 使用令牌：
游戏现在可以使用访问令牌从 Facebook（来自资源服务器）请求已经同意的数据，比如玩家的朋友列表。&lt;/p&gt;
&lt;p&gt;在这个过程中，玩家的 Facebook 凭证从未被共享，但游戏能够从 Facebook 访问到玩家同意的数据。这就是 OAuth 2.0 所做的事情；允许第三方应用程序以安全的方式从服务中访问数据，而无需共享凭证。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>分布式数据库特性介绍</title><link>https://blog.ithuo.net/posts/distributed-database-features-introduction/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/distributed-database-features-introduction/</guid><pubDate>Wed, 07 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;ACID vs BASE&lt;/h1&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ACID&lt;/th&gt;
&lt;th&gt;BASE&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;原子性(&lt;strong&gt;A&lt;/strong&gt;tomicity)&lt;/td&gt;
&lt;td&gt;基本可用(&lt;strong&gt;B&lt;/strong&gt;asically &lt;strong&gt;A&lt;/strong&gt;vailable)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;一致性(&lt;strong&gt;C&lt;/strong&gt;onsistency)&lt;/td&gt;
&lt;td&gt;软状态/柔性事务(&lt;strong&gt;S&lt;/strong&gt;oft state)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;隔离性(&lt;strong&gt;I&lt;/strong&gt;solation)&lt;/td&gt;
&lt;td&gt;最终一致性 (&lt;strong&gt;E&lt;/strong&gt;ventual consistency)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;持久性 (&lt;strong&gt;D&lt;/strong&gt;urable)&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;关系型数据库遵循ACID规则&lt;/h1&gt;
&lt;p&gt;事务在英文中是transaction，和现实世界中的交易很类似，它有如下四个特性：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1、A (Atomicity) 原子性&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;原子性很容易理解，也就是说事务里的所有操作要么全部做完，要么都不做，事务成功的条件是事务里的所有操作都成功，只要有一个操作失败，整个事务就失败，需要回滚。&lt;/p&gt;
&lt;p&gt;比如银行转账，从A账户转100元至B账户，分为两个步骤：1）从A账户取100元；2）存入100元至B账户。这两步要么一起完成，要么一起不完成，如果只完成第一步，第二步失败，钱会莫名其妙少了100元。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2、C (Consistency) 一致性&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;一致性也比较容易理解，也就是说数据库要一直处于一致的状态，事务的运行不会改变数据库原本的一致性约束。&lt;/p&gt;
&lt;p&gt;例如现有完整性约束a+b=10，如果一个事务改变了a，那么必须得改变b，使得事务结束后依然满足a+b=10，否则事务失败。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3、I (Isolation) 独立性&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;所谓的独立性是指并发的事务之间不会互相影响，如果一个事务要访问的数据正在被另外一个事务修改，只要另外一个事务未提交，它所访问的数据就不受未提交事务的影响。&lt;/p&gt;
&lt;p&gt;比如现在有个交易是从A账户转100元至B账户，在这个交易还未完成的情况下，如果此时B查询自己的账户，是看不到新增加的100元的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4、D (Durability) 持久性&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;持久性是指一旦事务提交后，它所做的修改将会永久的保存在数据库上，即使出现宕机也不会丢失。&lt;/p&gt;
&lt;h1&gt;RDBMS vs NoSQL&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;RDBMS&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;高度组织化结构化数据&lt;/li&gt;
&lt;li&gt;结构化查询语言（SQL） (SQL)&lt;/li&gt;
&lt;li&gt;数据和关系都存储在单独的表中。&lt;/li&gt;
&lt;li&gt;数据操纵语言，数据定义语言&lt;/li&gt;
&lt;li&gt;严格的一致性&lt;/li&gt;
&lt;li&gt;基础事务&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;NoSQL&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;代表着不仅仅是SQL&lt;/li&gt;
&lt;li&gt;没有声明性查询语言&lt;/li&gt;
&lt;li&gt;没有预定义的模式-键&lt;/li&gt;
&lt;li&gt;值对存储，列存储，文档存储，图形数据库&lt;/li&gt;
&lt;li&gt;最终一致性，而非ACID属性&lt;/li&gt;
&lt;li&gt;非结构化和不可预知的数据&lt;/li&gt;
&lt;li&gt;CAP定理&lt;/li&gt;
&lt;li&gt;高性能，高可用性和可伸缩性&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;NoSQL的优点/缺点&lt;/h1&gt;
&lt;p&gt;优点:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;高可扩展性&lt;/li&gt;
&lt;li&gt;分布式计算&lt;/li&gt;
&lt;li&gt;低成本&lt;/li&gt;
&lt;li&gt;架构的灵活性，半结构化数据&lt;/li&gt;
&lt;li&gt;没有复杂的关系&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;缺点:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;没有标准化&lt;/li&gt;
&lt;li&gt;有限的查询功能（到目前为止）&lt;/li&gt;
&lt;li&gt;最终一致是不直观的程序&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;BASE&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;BASE：Basically Available, Soft-state, Eventually Consistent。 由 Eric Brewer 定义。&lt;/li&gt;
&lt;li&gt;BASE是NoSQL数据库通常对可用性及一致性的弱要求原则:&lt;/li&gt;
&lt;li&gt;Basically Available --基本可用&lt;/li&gt;
&lt;li&gt;Soft-state --软状态/柔性事务。 &quot;Soft state&quot; 可以理解为&quot;无连接&quot;的, 而 &quot;Hard state&quot; 是&quot;面向连接&quot;的&lt;/li&gt;
&lt;li&gt;Eventually Consistency -- 最终一致性， 也是 ACID 的最终目的。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;CAP定理（CAP theorem）&lt;/h1&gt;
&lt;p&gt;在计算机科学中, CAP定理（CAP theorem）, 又被称作 布鲁尔定理（Brewer&apos;s theorem）, 它指出对于一个分布式计算系统来说，不可能同时满足以下三点:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;一致性(Consistency)&lt;/strong&gt;(所有节点在同一时间具有相同的数据)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可用性(Availability)&lt;/strong&gt;(保证每个请求不管成功或者失败都有响应)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;分隔容忍(Partition tolerance)&lt;/strong&gt;(系统中任意信息的丢失或失败不会影响系统的继续运作)&lt;/li&gt;
&lt;li&gt;CAP理论的核心是：一个分布式系统不可能同时很好的满足一致性，可用性和分区容错性这三个需求，最多只能同时较好的满足两个。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三 大类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CA - 单点集群，满足一致性，可用性的系统，通常在可扩展性上不太强大。&lt;/li&gt;
&lt;li&gt;CP - 满足一致性，分区容忍性的系统，通常性能不是特别高。&lt;/li&gt;
&lt;li&gt;AP - 满足可用性，分区容忍性的系统，通常可能对一致性要求低一些。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/f22e05d9d230a0c45c5ba311a0e9aee5.png&quot; alt=&quot;1620730300674-b82b3b9a-080a-485b-a8ad-710fd0a7e45b.png&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;分布式系统&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;分布式系统（distributed system）由多台计算机和通信的软件组件通过计算机网络连接（本地网络或广域网）组成。&lt;/li&gt;
&lt;li&gt;分布式系统是建立在网络之上的软件系统。正是因为软件的特性，所以分布式系统具有高度的内聚性和透明性。&lt;/li&gt;
&lt;li&gt;因此，网络和分布式系统之间的区别更多的在于高层软件（特别是操作系统），而不是硬件。&lt;/li&gt;
&lt;li&gt;分布式系统可以应用在不同的平台上如：Pc、工作站、局域网和广域网上等。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;分布式计算的优点&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;可靠性（容错） ：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;分布式计算系统中的一个重要的优点是可靠性。一台服务器的系统崩溃并不影响到其余的服务器。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;可扩展性：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在分布式计算系统可以根据需要增加更多的机器。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;资源共享：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;共享数据是必不可少的应用，如银行，预订系统。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;灵活性：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;由于该系统是非常灵活的，它很容易安装，实施和调试新的服务。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;更快的速度：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;分布式计算系统可以有多台计算机的计算能力，使得它比其他系统有更快的处理速度。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;开放系统：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;由于它是开放的系统，本地或者远程都可以访问到该服务。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;更高的性能：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;相较于集中式计算机网络集群可以提供更高的性能（及更好的性价比）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;分布式计算的缺点&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;故障排除：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;故障排除和诊断问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;软件：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;更少的软件支持是分布式计算系统的主要缺点。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;网络：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;网络基础设施的问题，包括：传输问题，高负载，信息丢失等。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;安全性：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;开放系统的特性让分布式计算系统存在着数据的安全性和共享的风险等问题。&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Derick</author></item><item><title>Mongodb学习笔记</title><link>https://blog.ithuo.net/posts/mongodb-learning-notes/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/mongodb-learning-notes/</guid><pubDate>Fri, 18 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;介绍&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;MongoDB 是由C++语言编写的，是一个基于分布式文件存储的开源数据库系统。&lt;/li&gt;
&lt;li&gt;在高负载的情况下，添加更多的节点，可以保证服务器性能。&lt;/li&gt;
&lt;li&gt;MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。&lt;/li&gt;
&lt;li&gt;MongoDB 将数据存储为一个文档，数据结构由键值(key=&amp;gt;value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档，数组及文档数组。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;主要特点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;MongoDB 是一个面向文档存储的数据库，操作起来比较简单和容易。&lt;/li&gt;
&lt;li&gt;你可以在MongoDB记录中设置任何属性的索引 (如：FirstName=&quot;Sameer&quot;,Address=&quot;8 Gandhi Road&quot;)来实现更快的排序。&lt;/li&gt;
&lt;li&gt;你可以通过本地或者网络创建数据镜像，这使得MongoDB有更强的扩展性。&lt;/li&gt;
&lt;li&gt;如果负载的增加（需要更多的存储空间和更强的处理能力） ，它可以分布在计算机网络中的其他节点上这就是所谓的分片。&lt;/li&gt;
&lt;li&gt;Mongo支持丰富的查询表达式。查询指令使用JSON形式的标记，可轻易查询文档中内嵌的对象及数组。&lt;/li&gt;
&lt;li&gt;MongoDb 使用update()命令可以实现替换完成的文档（数据）或者一些指定的数据字段 。&lt;/li&gt;
&lt;li&gt;Mongodb中的Map/reduce主要是用来对数据进行批量处理和聚合操作。&lt;/li&gt;
&lt;li&gt;Map和Reduce。Map函数调用emit(key,value)遍历集合中所有的记录，将key与value传给Reduce函数进行处理。&lt;/li&gt;
&lt;li&gt;Map函数和Reduce函数是使用Javascript编写的，并可以通过db.runCommand或mapreduce命令来执行MapReduce操作。&lt;/li&gt;
&lt;li&gt;GridFS是MongoDB中的一个内置功能，可以用于存放大量小文件。&lt;/li&gt;
&lt;li&gt;MongoDB允许在服务端执行脚本，可以用Javascript编写某个函数，直接在服务端执行，也可以把函数的定义存储在服务端，下次直接调用即可。&lt;/li&gt;
&lt;li&gt;MongoDB支持各种编程语言:RUBY，PYTHON，JAVA，C++，PHP，C#等多种语言。&lt;/li&gt;
&lt;li&gt;MongoDB安装简单。支持虚拟化，云原生环境&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;MongoDB概念解析&lt;/h3&gt;
&lt;p&gt;在mongodb中基本的概念是文档、集合、数据库，&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SQL术语/概念&lt;/th&gt;
&lt;th&gt;MongoDB术语/概念&lt;/th&gt;
&lt;th&gt;解释/说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;database&lt;/td&gt;
&lt;td&gt;database&lt;/td&gt;
&lt;td&gt;数据库&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;table&lt;/td&gt;
&lt;td&gt;collection&lt;/td&gt;
&lt;td&gt;数据库表/集合&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;row&lt;/td&gt;
&lt;td&gt;document&lt;/td&gt;
&lt;td&gt;数据记录行/文档&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;column&lt;/td&gt;
&lt;td&gt;field&lt;/td&gt;
&lt;td&gt;数据字段/域&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;index&lt;/td&gt;
&lt;td&gt;index&lt;/td&gt;
&lt;td&gt;索引&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;table joins&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;表连接,MongoDB不支持&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;primary key&lt;/td&gt;
&lt;td&gt;primary key&lt;/td&gt;
&lt;td&gt;主键,MongoDB自动将_id字段设置为主键&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;mongodb默认有以下数据库&lt;/h4&gt;
&lt;p&gt;有一些数据库名是保留的，可以直接访问这些有特殊作用的数据库。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;admin： 从权限的角度来看，这是&quot;root&quot;数据库。要是将一个用户添加到这个数据库，这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行，比如列出所有的数据库或者关闭服务器。&lt;/li&gt;
&lt;li&gt;local:这个数据永远不会被复制，可以用来存储限于本地单台服务器的任意集合&lt;/li&gt;
&lt;li&gt;config: 当Mongo用于分片设置时，config数据库在内部使用，用于保存分片的相关信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;需要注意的是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;文档中的键/值对是有序的。&lt;/li&gt;
&lt;li&gt;文档中的值不仅可以是在双引号里面的字符串，还可以是其他几种数据类型（甚至可以是整个嵌入的文档)。&lt;/li&gt;
&lt;li&gt;MongoDB区分类型和大小写。&lt;/li&gt;
&lt;li&gt;MongoDB的文档不能有重复的键。&lt;/li&gt;
&lt;li&gt;文档的键是字符串。除了少数例外情况，键可以使用任意UTF-8字符。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;文档键命名规范：&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;键不能含有\0 (空字符)。这个字符用来表示键的结尾。&lt;/li&gt;
&lt;li&gt;.和$有特别的意义，只有在特定环境下才能使用。&lt;/li&gt;
&lt;li&gt;以下划线&quot;_&quot;开头的键是保留的(不是严格要求的)。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;文档(Document)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;文档是一组键值(key-value)对(即 BSON)。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;集合(Collection)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;集合就是 MongoDB 文档组，类似于 RDBMS （关系数据库管理系统：Relational Database Management System)中的表格。&lt;/li&gt;
&lt;li&gt;集合存在于数据库中，集合没有固定的结构，这意味着你在对集合可以插入不同格式和类型的数据，但通常情况下我们插入集合的数据都会有一定的关联性。&lt;/li&gt;
&lt;li&gt;第一个文档插入时，集合就会被创建。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;合法的集合名&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;集合名不能是空字符串&quot;&quot;。&lt;/li&gt;
&lt;li&gt;集合名不能含有\0字符（空字符)，这个字符表示集合名的结尾。&lt;/li&gt;
&lt;li&gt;集合名不能以&quot;system.&quot;开头，这是为系统集合保留的前缀。&lt;/li&gt;
&lt;li&gt;用户创建的集合名字不能含有保留字符。有些驱动程序的确支持在集合名里面包含，这是因为某些系统生成的集合中包含该字符。除非你要访问这种系统创建的集合，否则千万不要在名字里出现$。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;MongoDB 数据类型&lt;/h4&gt;
&lt;p&gt;下表为MongoDB中常用的几种数据类型。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;数据类型&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;字符串。存储数据常用的数据类型。在 MongoDB 中，UTF-8 编码的字符串才是合法的。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Integer&lt;/td&gt;
&lt;td&gt;整型数值。用于存储数值。根据你所采用的服务器，可分为 32 位或 64 位。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Boolean&lt;/td&gt;
&lt;td&gt;布尔值。用于存储布尔值（真/假）。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Double&lt;/td&gt;
&lt;td&gt;双精度浮点值。用于存储浮点值。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Min/Max keys&lt;/td&gt;
&lt;td&gt;将一个值与 BSON（二进制的 JSON）元素的最低值和最高值相对比。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Array&lt;/td&gt;
&lt;td&gt;用于将数组或列表或多个值存储为一个键。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timestamp&lt;/td&gt;
&lt;td&gt;时间戳。记录文档修改或添加的具体时间。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Object&lt;/td&gt;
&lt;td&gt;用于内嵌文档。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Null&lt;/td&gt;
&lt;td&gt;用于创建空值。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Symbol&lt;/td&gt;
&lt;td&gt;符号。该数据类型基本上等同于字符串类型，但不同的是，它一般用于采用特殊符号类型的语言。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Date&lt;/td&gt;
&lt;td&gt;日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间：创建 Date 对象，传入年月日信息。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Object ID&lt;/td&gt;
&lt;td&gt;对象 ID。用于创建文档的 ID。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Binary Data&lt;/td&gt;
&lt;td&gt;二进制数据。用于存储二进制数据。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code&lt;/td&gt;
&lt;td&gt;代码类型。用于在文档中存储 JavaScript 代码。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Regular expression&lt;/td&gt;
&lt;td&gt;正则表达式类型。用于存储正则表达式。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;ObjectId&lt;/h4&gt;
&lt;p&gt;ObjectId 类似唯一主键，可以很快的去生成和排序，包含 12 bytes，含义是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;前 4 个字节表示创建unix时间戳,格林尼治时间UTC时间，比北京时间晚了 8 个小时&lt;/li&gt;
&lt;li&gt;接下来的 3 个字节是机器标识码&lt;/li&gt;
&lt;li&gt;紧接的两个字节由进程 id 组成 PID&lt;/li&gt;
&lt;li&gt;最后三个字节是随机数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/c2be9f86f4004e2f58fa7de70b899135.jpeg&quot; alt=&quot;1620731779142-4439a94d-d3e5-44b3-b32f-4a01685db860.jpeg&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MongoDB 中存储的文档必须有一个 _id 键。这个键的值可以是任何类型的，默认是个 ObjectId 对象&lt;/li&gt;
&lt;li&gt;由于 ObjectId 中保存了创建的时间戳，所以你不需要为你的文档保存时间戳字段，你可以通过 getTimestamp 函数来获取文档的创建时间:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; var newObject = ObjectId()

&amp;gt; newObject.getTimestamp()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ISODate(&quot;2017-11-25T07:21:10Z&quot;)&lt;/p&gt;
&lt;p&gt;ObjectId 转为字符串&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; newObject.str

5a1919e63df83ce79df8b38f
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;时间戳&lt;/p&gt;
&lt;p&gt;BSON 有一个特殊的时间戳类型用于 MongoDB 内部使用，与普通的 日期 类型不相关。 时间戳值是一个 64 位的值。其中：&lt;/p&gt;
&lt;p&gt;●前32位是一个 time_t 值（与Unix新纪元相差的秒数）&lt;/p&gt;
&lt;p&gt;●后32位是在某秒中操作的一个递增的序数&lt;/p&gt;
&lt;p&gt;在单个 mongod 实例中，时间戳值通常是唯一的。&lt;/p&gt;
&lt;p&gt;在复制集中， oplog 有一个 ts 字段。这个字段中的值使用BSON时间戳表示了操作时间。&lt;/p&gt;
&lt;p&gt;BSON 时间戳类型主要用于 MongoDB 内部使用。在大多数情况下的应用开发中，你可以使用 BSON 日期类型。&lt;/p&gt;
&lt;p&gt;字符串&lt;/p&gt;
&lt;p&gt;BSON 字符串都是 UTF-8 编码。&lt;/p&gt;
&lt;p&gt;日期&lt;/p&gt;
&lt;p&gt;表示当前距离 Unix新纪元（1970年1月1日）的毫秒数。日期类型是有符号的, 负数表示 1970 年之前的日期。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;//显示所有数据库
show dbs;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>Derick</author></item><item><title>Web3架构分析</title><link>https://blog.ithuo.net/posts/web3-architecture-analysis/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/web3-architecture-analysis/</guid><pubDate>Wed, 16 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;ul&gt;
&lt;li&gt;Web 3.0应用程序（或“DApps”）的架构与Web 2.0应用程序完全不同。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以Medium为例，它是一个简单的博客网站，允许用户发布自己的内容并与其他人的内容进行交互。&lt;/p&gt;
&lt;p&gt;作为一个web 2.0应用程序，这听起来可能很简单，但Medium的架构中有很多东西使这一切成为可能：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;首先，必须有一个地方存储必要的数据，如用户，帖子，标签，评论，喜欢等。这需要一个不断更新的数据库。&lt;/li&gt;
&lt;li&gt;其次，后端代码（用Node.js、Java或Python等语言编写）必须定义Medium的业务逻辑。例如，当一个新用户注册、发布新博客或在其他人的博客上发表评论时，会发生什么？&lt;/li&gt;
&lt;li&gt;第三，前端代码（通常用JavaScript、HTML和CSS编写）必须定义Medium的UI逻辑。例如，网站是什么样子的，当用户与页面上的每个元素交互时会发生什么？&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;把所有这些放在一起，当你在Medium上写一篇博客文章时，你与它的前端交互，它与它的后端对话，它与它的数据库对话。所有这些代码都托管在集中式服务器上，并通过互联网浏览器发送给用户。这是对当今大多数Web 2.0应用程序如何工作的一个很好的技术概括。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/a3a4161a8325913a887b9be2104e1e1a.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;区块链技术为Web 3.0应用程序开启了一个令人兴奋的新方向。在本文中，我们将重点关注以太坊区块链带来的东西。&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;是什么让Web 3.0与众不同？&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;与Medium等Web 2.0应用程序不同，Web 3.0消除了中间人，没有存储应用程序状态的集中式数据库，也没有后端逻辑所在的集中式Web服务器。&lt;/p&gt;
&lt;p&gt;相反，您可以利用区块链在由互联网上的匿名节点维护的分散状态机上构建应用程序。&lt;/p&gt;
&lt;p&gt;所谓“状态机”，我指的是一台机器，它维护某些给定的程序状态和该机器上允许的未来状态。区块链是用一些起源状态实例化的状态机，并且具有非常严格的规则（即，共识），定义该状态如何转换。&lt;/p&gt;
&lt;p&gt;更好的是，没有单一实体控制这个分散的状态机-它由网络中的每个人共同维护。&lt;/p&gt;
&lt;p&gt;那么后端服务器呢？在Web 3.0中，你可以编写智能合约来定义应用程序的逻辑，并将它们部署到分散的状态机上，而不是像Medium那样控制后端。这意味着每个想要构建区块链应用程序的人都将他们的代码部署在这个共享状态机上。&lt;/p&gt;
&lt;p&gt;前端呢？它几乎保持不变，除了一些例外，我们将在后面介绍。这是新架构的样子&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/824cc21d557bc071df85e4bd6d7ac5ef.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;1) Blockchain&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;以太坊区块链经常被吹捧为“世界计算机”。这是因为它是一个全局可访问的、确定性的状态机，由对等节点网络维护。这个状态机上的状态变化由网络中的对等点遵循的共识规则来控制。&lt;/p&gt;
&lt;p&gt;所以，换句话说，它实际上被设计成一个状态机，世界上任何人都可以访问和写入。因此，这台机器不属于任何单一实体，而是由网络中的每个人共同拥有。&lt;/p&gt;
&lt;p&gt;还有一件事要知道：数据只能写入以太坊区块链-您永远无法更新现有数据。&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;2) Smart contracts&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;智能合约是一个在以太坊区块链上运行的程序，它定义了区块链上发生的状态变化背后的逻辑。智能合约是用高级语言编写的，如Solidity或Vyper。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/ae377dbad6bd34021bf38dd42c3811e4.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;由于智能合约代码存储在以太坊区块链上，任何人都可以检查网络上所有智能合约的应用逻辑。&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;3) Ethereum Virtual Machine (EVM)&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;接下来，你有以太坊虚拟机，它执行智能合约中定义的逻辑，并处理在这个全局可访问的状态机上发生的状态更改。&lt;/p&gt;
&lt;p&gt;EVM不理解Solidity和Vyper等用于编写智能合约的高级语言。相反，您必须将高级语言编译成字节码，然后EVM可以执行这些字节码。&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;4) Front-end&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;最后，我们有前端。正如我们之前提到的，它定义了UI逻辑，但前端也与智能合约中定义的应用程序逻辑进行通信。&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;前端代码如何与以太坊上的智能合约通信？&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;我们希望我们的前端与我们的智能合约通信，以便它们可以调用函数，但请记住，以太坊是一个去中心化的网络。以太坊网络中的每个节点都保留了以太坊状态机上所有状态的副本，包括与每个智能合约相关的代码和数据。&lt;/p&gt;
&lt;p&gt;当我们想要与区块链上的数据和代码进行交互时，我们需要与其中一个节点进行交互。这是因为任何节点都可以广播在EVM上执行事务的请求。然后，矿工将执行交易，并将由此产生的状态变化传播到网络的其余部分。&lt;/p&gt;
&lt;p&gt;有两种方法可以广播新交易：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;设置您自己的节点，运行以太坊区块链软件&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;使用Infura、Alchemy和Quicknode等第三方服务提供的节点&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果您使用第三方服务，则不必自己处理运行完整节点的所有头痛问题。毕竟，在自己的服务器上设置一个新的以太坊节点可能需要几天时间。（有很多数据要同步-它甚至可以占用更多的带宽和存储比典型的笔记本电脑可以处理。&lt;/p&gt;
&lt;p&gt;此外，存储完整以太坊区块链的成本随着DApp的扩展而增加，并且您需要添加更多节点来扩展基础设施。这就是为什么随着基础设施变得越来越复杂，您需要全职的DevOps工程师。他们将帮助您维护基础架构，确保可靠的数据传输和快速响应。&lt;/p&gt;
&lt;p&gt;总而言之，避免这些令人头痛的问题就是为什么许多DApp选择使用Infura或Alchemy等服务来管理他们的节点基础设施。当然，这是一个权衡，因为这会创建一个集中的阻塞点，但让我们把这个兔子洞留到另一天。;）&lt;/p&gt;
&lt;p&gt;接下来，让我们谈谈供应商。当您需要与区块链进行交互时，您连接的节点（无论是您自己设置还是使用第三方服务的现有节点）通常被称为“提供者”。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/0261afa14b40e189694328ab5a69d77a.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;每个以太坊客户端（即提供者）都实现了JSON-RPC规范。这确保了当前端应用程序想要与区块链交互时，有一组统一的方法。如果您需要了解JSON-RPC，它是一种无状态的轻量级远程过程调用（RPC）协议，定义了几种数据结构及其处理规则。它是与传输无关的，因此这些概念可以在同一进程中、通过套接字、通过HTTP或在许多不同的消息传递环境中使用。它使用JSON（RFC 4627）作为数据格式。&lt;/p&gt;
&lt;p&gt;一旦您通过提供程序连接到区块链，您就可以读取存储在区块链上的状态。但是如果你想写状态，在你把交易提交到区块链之前，还有一件事需要做--使用你的私钥对交易进行“签名”。&lt;/p&gt;
&lt;p&gt;例如，假设我们有一个DApp，它允许用户阅读或发布博客文章到区块链。你可能在前端有一个按钮，允许任何人查询特定用户写的博客文章。（回想一下，从区块链中阅读并不需要用户签署交易。&lt;/p&gt;
&lt;p&gt;然而，当用户想要在链上发布新帖子时，我们的DApp会要求用户使用他们的私钥“签名”交易-只有这样DApp才会将交易中继到区块链。否则，节点不会接受交易。&lt;/p&gt;
&lt;p&gt;这种交易的“签名”是Metamask通常使用的方法。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/ac7fa20c83366b63645ace1b7dcc2e94.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Metamask是一个工具，可以让应用程序轻松处理密钥管理和事务签名。很简单：Metamask将用户的私钥存储在浏览器中，每当前端需要用户签署交易时，它就会调用Metamask。&lt;/p&gt;
&lt;p&gt;Metamask还提供了与区块链的连接（作为“提供者”），因为它已经与Infura提供的节点建立了连接，因为它需要它来签署交易。通过这种方式，Metamask既是提供者又是签名者。🤯&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;区块链上的存储&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;如果你正在构建一个所有智能合约和数据都完全位于以太坊区块链上的应用程序，那么这种架构是有意义的。但任何在以太坊上构建应用程序的人都知道，将所有东西存储在区块链上会变得非常昂贵，非常快。&lt;/p&gt;
&lt;p&gt;请记住，使用以太坊，用户每次向区块链添加新数据时都要付费。这是因为向去中心化状态机添加状态会增加维护该状态机的节点的成本。&lt;/p&gt;
&lt;p&gt;要求用户在每次交易需要添加新状态时为使用DApp支付额外费用并不是最好的用户体验。解决这个问题的一种方法是使用分散的链下存储解决方案，如IPFS或Swarm。&lt;/p&gt;
&lt;p&gt;IPFS是一种用于存储和访问数据的分布式文件系统。因此，IPFS系统不是将数据存储在集中式数据库中，而是将数据分发和存储在对等网络中。这使得它很容易为您检索它当你需要的。&lt;/p&gt;
&lt;p&gt;IPFS还有一个激励层，称为“Filecoin”。这一层激励世界各地的节点存储和检索这些数据。您可以使用Infura（为您提供IPFS节点）或Pinata（提供易于使用的服务，您可以将文件“固定”到IPFS并将IPFS哈希存储在区块链上）等提供商。&lt;/p&gt;
&lt;p&gt;Swarm与之相似，因为它是一个分散的存储网络，但有一个显著的区别。虽然Filecoin是一个独立的系统，但Swarm的激励系统是内置的，并通过以太坊区块链上的智能合约来执行，用于存储和检索数据。&lt;/p&gt;
&lt;p&gt;所以现在，使用IPFS或Swarm，我们的应用程序架构看起来像这样：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/bac9f855fe04c369d9996e20e8701594.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;敏锐的读者可能也注意到下图中的前端代码并没有存储在区块链上。我们可以将这些代码托管在AWS上，就像我们在Web 2.0中通常做的那样，但这会为您的DApp创建一个集中化的瓶颈。如果AWS崩溃了呢？如果它审查你的应用程序怎么办？&lt;/p&gt;
&lt;p&gt;这就是为什么，如果你想构建一个真正去中心化的应用程序，你可能会选择在去中心化的存储解决方案上托管你的前端，比如IPFS或Swarm。&lt;/p&gt;
&lt;p&gt;所以现在你的应用程序架构看起来更像这样：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/a8d7a40d758bf8f2c998eb0fb399d21e.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;查询区块链&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;到目前为止，我们已经讨论了如何通过签署交易并将其发送到区块链来写入区块链。但是从区块链上的智能合约中阅读数据呢？有两种主要方法可以做到这一点：&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;1) Smart Contract Events&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;您可以使用Web3.js库来查询和侦听智能合约事件。您可以侦听特定的事件，并在每次触发事件时指定回调。例如，如果你有一个智能合约，它在每个区块都从人A向人B发送连续的支付流，那么你可以在每次向人B进行新的支付时发出一个事件。你的前端代码可以监听智能合约触发的事件，并根据它执行特定的操作。&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;2) The Graph&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;上述方法有效，但有一些局限性。例如，如果你部署了一个智能合约，后来意识到你需要一个你最初没有包含的事件，那该怎么办？不幸的是，你必须重新部署一个包含该事件和数据的新智能合约。此外，使用回调来处理各种UI逻辑很快就会变得非常复杂。&lt;/p&gt;
&lt;p&gt;Graph是一种链下索引解决方案，可以更轻松地查询以太坊区块链上的数据。Graph允许您定义要索引哪些智能合约，要侦听哪些事件和函数调用，以及如何将传入事件转换为前端逻辑（或任何使用API的内容）可以使用的实体。它使用GraphQL作为查询语言，许多前端工程师喜欢它，因为与传统的REST API相比，它的表现力更强。&lt;/p&gt;
&lt;p&gt;通过对区块链数据进行索引，The Graph让我们可以在应用程序逻辑中以低延迟查询链上数据。&lt;/p&gt;
&lt;p&gt;现在，你的DApp架构看起来像这样：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/ac505e1ab2be5375bcaa7d6ef8ad1b5a.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;扩展您的DApp&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/716288271bc6d64efe36fd6e54e3d40d.png&quot; alt=&quot;614bb01a6931be1460c09ea1_Screen%20Shot%202021-09-22%20at%206.35.40%20PM.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;以太坊平均天然气价格&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/4751d009919362f5e793acb1abe22c44.png&quot; alt=&quot;614bb025db602667fe148215_Screen%20Shot%202021-09-22%20at%206.36.22%20PM.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;平均交易费&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/3731ff43bf8f8fd65de6a277e06e3700.png&quot; alt=&quot;614bb0800062b65784ec410a_Screen%20Shot%202021-09-22%20at%206.38.41%20PM.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;平均数据块大小&lt;/p&gt;
&lt;p&gt;在以太坊上构建一个DApp，使用高额的天然气费用和完整的区块会导致非常糟糕的用户体验。幸运的是，有一些解决方案正在开发中。&lt;/p&gt;
&lt;p&gt;一种流行的缩放解决方案是Polygon，一种L2缩放解决方案。Polygon不是在主区块链上执行交易，而是拥有处理和执行交易的“侧链”。侧链是与主链连接的二级区块链。每隔一段时间，侧链就会将其最近区块的聚合提交回主链。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/00fad7f48c64b9afe340f91aff0f3fc4.png&quot; alt=&quot;614bb0df53dcfec13ea9f668_Screen%20Shot%202021-09-22%20at%206.40.09%20PM.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;L2解决方案的其他示例是乐观Rollup和zkRollup。这里的想法是类似的：我们使用“汇总”智能合约在链下批量处理交易，然后定期将这些交易提交到主链。想法是这样的：L2解决方案执行事务（即，慢的部分）是链下的，只有交易数据存储在链上。这让我们可以扩展区块链，因为我们不必在链上执行每一笔交易。这也使得交易更快，更便宜-并且在必要时仍然可以与主以太坊区块链进行通信。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/6fd923851c546794e9f5855df9e058c1.png&quot; alt=&quot;614bb2efff06e818e12a57f2_Screen%20Shot%202021-09-22%20at%206.49.04%20PM.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;组合在一起&lt;/h3&gt;
&lt;p&gt;例如，Hardhat是一个开发者框架，使以太坊开发者更容易构建、部署和测试他们的智能合约。Hardhat提供了“Hardhat Network”，开发人员可以使用它将智能合约部署到本地网络上，而无需处理实时环境。更好的是，它提供了一个伟大的插件生态系统，使开发人员的生活更容易。Hardhat还提供了 &lt;code&gt;console.log()&lt;/code&gt;  功能，类似于JavaScript，用于调试目的。&lt;/p&gt;
&lt;h3&gt;结论&lt;/h3&gt;
&lt;p&gt;大多数人花了几个月的时间来弄清楚工具链是如何工作的，所以如果你是一个新的DApp开发人员，我希望这篇文章能为你节省一些时间。是时候开始建造了！&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>URL的组成部分</title><link>https://blog.ithuo.net/posts/components-of-url/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/components-of-url/</guid><pubDate>Sun, 13 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;什么是URL？&lt;/h3&gt;
&lt;p&gt;URL代表互联网上资源的位置（网页，图像，文件等）。当你输入URL时，你的浏览器会通过计算机网络来检索该位置的资源。&lt;/p&gt;
&lt;p&gt;URL的组成部分（按顺序）：&lt;/p&gt;
&lt;p&gt;🔸 协议/方案：这代表用于获取资源的方法。例如，HTTP，HTTPS或FTP。&lt;/p&gt;
&lt;p&gt;🔸 子域：它位于域名之前，是可选的。它用于组织网站的不同部分。&lt;/p&gt;
&lt;p&gt;🔸 域名：存储网站或资源的服务器的位置。这是用来代替服务器的IP地址以提高可读性。&lt;/p&gt;
&lt;p&gt;🔸 路径：指定了Web服务器上的特定资源。&lt;/p&gt;
&lt;p&gt;🔸 查询字符串：用于向服务器发送额外的信息。以“？”开头，并由键值对组成（例如；?search=hat&amp;amp;color=blue）。&lt;/p&gt;
&lt;p&gt;🔸 片段/锚定：这是可选的，位于“#”之后。它用于让浏览器知道一旦网页加载完毕，就滚动到网页的特定部分。&lt;/p&gt;
&lt;h3&gt;举例&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.ithuo.net/post/2022-12-07%2F%E4%BB%80%E4%B9%88%E6%98%AFOAuth2.0&quot;&gt;https://blog.ithuo.net/post/2022-12-07%2F%E4%BB%80%E4%B9%88%E6%98%AFOAuth2.0&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTTPS&lt;/li&gt;
&lt;li&gt;blog&lt;/li&gt;
&lt;li&gt;ithuo.net&lt;/li&gt;
&lt;li&gt;post/2022-12-07… 为路径&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Citations:
[1] &lt;a href=&quot;https://www.seobility.net/en/wiki/URL&quot;&gt;https://www.seobility.net/en/wiki/URL&lt;/a&gt;
[2] &lt;a href=&quot;https://www.ibm.com/docs/en/cics-ts/5.1?topic=concepts-components-url&quot;&gt;https://www.ibm.com/docs/en/cics-ts/5.1?topic=concepts-components-url&lt;/a&gt;
[3] &lt;a href=&quot;https://www.geeksforgeeks.org/components-of-a-url/&quot;&gt;https://www.geeksforgeeks.org/components-of-a-url/&lt;/a&gt;
[4] &lt;a href=&quot;https://blog.hubspot.com/marketing/parts-url&quot;&gt;https://blog.hubspot.com/marketing/parts-url&lt;/a&gt;
[5] &lt;a href=&quot;https://www.techtarget.com/searchnetworking/definition/URL&quot;&gt;https://www.techtarget.com/searchnetworking/definition/URL&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>探讨无状态设计</title><link>https://blog.ithuo.net/posts/exploring-stateless-design/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/exploring-stateless-design/</guid><pubDate>Thu, 10 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;&lt;strong&gt;A Look Into Stateless Design&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;无状态设计是一种强大的模型，它促进产生了简单但高度可扩展且高效的应用程序的开发。&lt;/p&gt;
&lt;p&gt;“状态”是指系统用于处理请求的存储信息。当用户与应用程序交互或系统事件发生时，此信息可能会随着时间而变化。&lt;/p&gt;
&lt;p&gt;在我们深入研究无状态设计的细节之前，让我们先看一下替代方案——有状态应用程序。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;什么是有状态应用程序？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对于有状态应用程序，可以存储用户 ID、会话信息、配置和首选项等客户端数据，以帮助处理给定用户的请求。根据应用程序的功能和要求，可能会保存其他数据，例如在线商店的购物车信息或金融科技服务的交易历史记录。&lt;/p&gt;
&lt;p&gt;有状态设计允许应用程序为其用户提供个性化体验，同时消除在多个请求之间共享数据的需要。因此，对于流媒体服务和在线游戏等具有用户偏好的应用程序来说，这是一种流行的方法。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/66d84fb6c39854dfc1f63f7fa39e6610.jpg&quot; alt=&quot;IMG_2811_2.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;无状态设计的诞生&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;随着应用程序变得越来越复杂并收到越来越多的流量，有状态设计的局限性变得显而易见。管理和维护会话数据会显着增加系统的性能开销和复杂性。这种复杂性使得系统难以水平扩展，因为跨多个实例共享状态成为一个挑战。&lt;/p&gt;
&lt;p&gt;对可扩展性和效率的快速需求推动了无状态设计的流行。请求没有包含状态管理机制，而是包含处理它所需的所有信息。这使得系统能够处理高水平的请求，同时增加系统扩展的灵活性，从而提高资源效率。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;无状态设计的用例&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;无状态设计由于符合无服务器架构和微服务等现代计算趋势而越来越受欢迎。微服务背后的关键原则之一是每个服务都是无状态的。这使得微服务能够独立扩展并确保资源消耗保持高效。无服务器计算遵循相同的概念——每个函数都是独立调用的。&lt;/p&gt;
&lt;p&gt;即使是需要会话管理的应用程序也可以从在其系统组件中实现无状态设计中受益。例如，大多数 RESTful API 都是无状态的，其中每个 API 调用都包含所有必要的信息。内容分发网络 (CDN) 还遵循无状态设计，以便网络中的任何服务器都可以满足每个请求，而无需在所有服务器之间同步会话数据或查询单个会话管理存储。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;无状态设计的缺点&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在无状态设计中，请求的大小可能会大得多。此外，跨多个请求发送数据可能会导致明显的低效率，其效率远远高于从中央存储系统管理和查询该数据的替代方案。&lt;/p&gt;
&lt;p&gt;值得注意的是，无状态设计只能针对真正无状态的用例来实现。尽管有状态设计有其缺点，但解决方法可能会增加更多的复杂性和脆弱性。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;最后的想法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;大多数应用程序根据每个组件的需求和约束选择有状态和无状态设计之间的混合方法。设计良好的系统的关键是平衡。它应该是可扩展的、简单的、快速的，并且不牺牲功能。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程: 使用WaitGroup和原子操作</title><link>https://blog.ithuo.net/posts/go-language-tutorial-using-waitgroup-and-atomic-operations/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-language-tutorial-using-waitgroup-and-atomic-operations/</guid><pubDate>Wed, 01 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;1. WaitGroup的使用&lt;/h3&gt;
&lt;p&gt;在这个例子中,我们使用了&lt;code&gt;sync.WaitGroup&lt;/code&gt;来协调多个goroutine的执行。WaitGroup就像一个计数器,我们可以通过它来等待一组goroutine完成。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var wg sync.WaitGroup
wg.Add(stride)  // 增加计数
go someFunction(wg.Done)  // 传入Done函数
wg.Wait()  // 等待所有goroutine完成
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;WaitGroup的工作原理:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用&lt;code&gt;Add()&lt;/code&gt;方法设置需要等待的goroutine数量&lt;/li&gt;
&lt;li&gt;每个goroutine完成时调用&lt;code&gt;Done()&lt;/code&gt;方法&lt;/li&gt;
&lt;li&gt;主goroutine调用&lt;code&gt;Wait()&lt;/code&gt;方法等待,直到计数器变为0&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这种机制非常适合需要等待多个并发任务完成的场景。例如,你可以用它来等待多个网络请求完成,或者等待多个文件处理任务结束。&lt;/p&gt;
&lt;h3&gt;2. 原子操作&lt;/h3&gt;
&lt;p&gt;代码中使用了&lt;code&gt;atomic&lt;/code&gt;包来进行原子操作,这是为了避免多个goroutine同时修改共享变量时可能出现的竞态条件。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;currNum := atomic.LoadInt32(numP)
if atomic.CompareAndSwapInt32(numP, currNum, newNum) {
    // 操作成功
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;原子操作的重要性:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;保证读取和修改操作的原子性&lt;/li&gt;
&lt;li&gt;避免数据竞争,确保数据一致性&lt;/li&gt;
&lt;li&gt;比使用互斥锁更轻量级,性能更好&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;除了&lt;code&gt;LoadInt32&lt;/code&gt;和&lt;code&gt;CompareAndSwapInt32&lt;/code&gt;,atomic包还提供了&lt;code&gt;AddInt32&lt;/code&gt;, &lt;code&gt;StoreInt32&lt;/code&gt;等方法。这些方法可以用于各种需要原子操作的场景,如计数器、标志位等。&lt;/p&gt;
&lt;h3&gt;3. 比较并交换(CAS)操作&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;CompareAndSwapInt32&lt;/code&gt;是一个比较并交换的操作,它的工作原理是:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;比较当前值是否等于期望值&lt;/li&gt;
&lt;li&gt;如果相等,则将新值写入&lt;/li&gt;
&lt;li&gt;如果不相等,则不做任何操作&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这个操作是原子的,可以用来实现无锁算法。在高并发情况下,CAS操作可以提高性能,因为它避免了线程阻塞。&lt;/p&gt;
&lt;h3&gt;4. defer的使用&lt;/h3&gt;
&lt;p&gt;代码中使用了&lt;code&gt;defer&lt;/code&gt;来确保&lt;code&gt;Done()&lt;/code&gt;方法被调用:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;defer func() {
    deferFunc()
}()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;defer的特点:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在函数返回前执行&lt;/li&gt;
&lt;li&gt;可以用来释放资源、解锁等清理操作&lt;/li&gt;
&lt;li&gt;多个defer语句按LIFO(后进先出)顺序执行&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;除了用于WaitGroup,defer还常用于文件操作、数据库连接等需要确保资源释放的场景。&lt;/p&gt;
&lt;h3&gt;5. 应用场景&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;并发下载:
你可以使用类似的方式来并发下载多个文件,每个下载任务启动一个goroutine,使用WaitGroup等待所有下载完成。&lt;/li&gt;
&lt;li&gt;并行计算:
在进行大规模数据处理时,可以将数据分片,每个分片启动一个goroutine进行处理,最后汇总结果。&lt;/li&gt;
&lt;li&gt;定时任务:
你可以结合time.Ticker实现定期执行的并发任务,每次触发时启动多个goroutine执行任务。&lt;/li&gt;
&lt;li&gt;生产者-消费者模型:
使用channel和goroutine可以轻松实现生产者-消费者模型,WaitGroup可以用来等待所有消费者处理完毕。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;通过这个例子,我们可以看到Go语言在并发编程方面的强大能力。合理使用goroutine、WaitGroup和原子操作,可以编写出高效、安全的并发程序。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：深入浅出sync.Once</title><link>https://blog.ithuo.net/posts/go-tutorial-understanding-sync-once-with-examples/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-tutorial-understanding-sync-once-with-examples/</guid><pubDate>Tue, 31 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在Go语言中，&lt;code&gt;sync.Once&lt;/code&gt;是一个非常有用的工具，它可以确保某个操作只执行一次。无论有多少个goroutine调用它，操作都只会执行一次。本文将通过几个示例代码，深入浅出地介绍&lt;code&gt;sync.Once&lt;/code&gt;的使用和原理。&lt;/p&gt;
&lt;h2&gt;示例1：基本使用&lt;/h2&gt;
&lt;p&gt;首先，我们来看一个简单的例子：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;fmt&quot;
	&quot;sync&quot;
	&quot;sync/atomic&quot;
)

func main() {
	var counter uint32
	var once sync.Once

	once.Do(func() {
		atomic.AddUint32(&amp;amp;counter, 1)
	})
	fmt.Printf(&quot;The counter: %d\\n&quot;, counter)

	once.Do(func() {
		atomic.AddUint32(&amp;amp;counter, 2)
	})
	fmt.Printf(&quot;The counter: %d\\n&quot;, counter)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;解释&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;定义变量&lt;/strong&gt;：我们定义了一个&lt;code&gt;uint32&lt;/code&gt;类型的变量&lt;code&gt;counter&lt;/code&gt;和一个&lt;code&gt;sync.Once&lt;/code&gt;类型的变量&lt;code&gt;once&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;第一次调用&lt;/strong&gt;**&lt;code&gt;once.Do&lt;/code&gt;**：我们传入一个匿名函数，该函数将&lt;code&gt;counter&lt;/code&gt;加1。由于这是第一次调用&lt;code&gt;once.Do&lt;/code&gt;，所以这个操作会执行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;第二次调用&lt;/strong&gt;**&lt;code&gt;once.Do&lt;/code&gt;**：我们再次传入一个匿名函数，这次将&lt;code&gt;counter&lt;/code&gt;加2。然而，由于&lt;code&gt;sync.Once&lt;/code&gt;的特性，这个操作不会执行。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;输出结果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;The counter: 1
The counter: 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看到，第二次调用&lt;code&gt;once.Do&lt;/code&gt;并没有改变&lt;code&gt;counter&lt;/code&gt;的值。&lt;/p&gt;
&lt;h2&gt;示例2：多goroutine并发&lt;/h2&gt;
&lt;p&gt;接下来，我们来看一个多goroutine并发的例子：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;fmt&quot;
	&quot;sync&quot;
	&quot;time&quot;
)

func main() {
	var once sync.Once
	var wg sync.WaitGroup

	wg.Add(3)

	go func() {
		defer wg.Done()
		once.Do(func() {
			for i := 0; i &amp;lt; 3; i++ {
				fmt.Printf(&quot;Do task. [1-%d]\\n&quot;, i)
				time.Sleep(time.Second)
			}
		})
		fmt.Println(&quot;Done. [1]&quot;)
	}()

	go func() {
		defer wg.Done()
		time.Sleep(time.Millisecond * 500)
		once.Do(func() {
			fmt.Println(&quot;Do task. [2]&quot;)
		})
		fmt.Println(&quot;Done. [2]&quot;)
	}()

	go func() {
		defer wg.Done()
		time.Sleep(time.Millisecond * 500)
		once.Do(func() {
			fmt.Println(&quot;Do task. [3]&quot;)
		})
		fmt.Println(&quot;Done. [3]&quot;)
	}()

	wg.Wait()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;解释&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;定义变量&lt;/strong&gt;：我们定义了一个&lt;code&gt;sync.Once&lt;/code&gt;类型的变量&lt;code&gt;once&lt;/code&gt;和一个&lt;code&gt;sync.WaitGroup&lt;/code&gt;类型的变量&lt;code&gt;wg&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;添加goroutine&lt;/strong&gt;：我们启动了三个goroutine，每个goroutine都会调用&lt;code&gt;once.Do&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;执行任务&lt;/strong&gt;：只有第一个goroutine中的任务会被执行，其他两个goroutine中的任务不会被执行。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;输出结果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Do task. [1-0]
Do task. [1-1]
Do task. [1-2]
Done. [1]
Done. [2]
Done. [3]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看到，只有第一个goroutine中的任务被执行了，其他两个goroutine中的任务没有被执行。&lt;/p&gt;
&lt;h2&gt;示例3：处理panic&lt;/h2&gt;
&lt;p&gt;最后，我们来看一个处理&lt;code&gt;panic&lt;/code&gt;的例子：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;errors&quot;
	&quot;fmt&quot;
	&quot;sync&quot;
	&quot;time&quot;
)

func main() {
	var once sync.Once
	var wg sync.WaitGroup

	wg.Add(2)

	go func() {
		defer wg.Done()
		defer func() {
			if p := recover(); p != nil {
				fmt.Printf(&quot;fatal error: %v\\n&quot;, p)
			}
		}()
		once.Do(func() {
			fmt.Println(&quot;Do task. [4]&quot;)
			panic(errors.New(&quot;something wrong&quot;))
			fmt.Println(&quot;Done. [4]&quot;)
		})
	}()

	go func() {
		defer wg.Done()
		time.Sleep(time.Millisecond * 500)
		once.Do(func() {
			fmt.Println(&quot;Do task. [5]&quot;)
		})
		fmt.Println(&quot;Done. [5]&quot;)
	}()

	wg.Wait()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;解释&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;定义变量&lt;/strong&gt;：我们定义了一个&lt;code&gt;sync.Once&lt;/code&gt;类型的变量&lt;code&gt;once&lt;/code&gt;和一个&lt;code&gt;sync.WaitGroup&lt;/code&gt;类型的变量&lt;code&gt;wg&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;添加goroutine&lt;/strong&gt;：我们启动了两个goroutine，第一个goroutine会触发&lt;code&gt;panic&lt;/code&gt;，第二个goroutine会等待500毫秒后调用&lt;code&gt;once.Do&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;处理&lt;/strong&gt;**&lt;code&gt;panic&lt;/code&gt;**：第一个goroutine中的任务会触发&lt;code&gt;panic&lt;/code&gt;，我们使用&lt;code&gt;recover&lt;/code&gt;来捕获并处理这个&lt;code&gt;panic&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;输出结果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Do task. [4]
fatal error: something wrong
Done. [5]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看到，第一个goroutine中的任务触发了&lt;code&gt;panic&lt;/code&gt;，但第二个goroutine中的任务仍然没有被执行。&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;通过以上三个示例，我们可以看到&lt;code&gt;sync.Once&lt;/code&gt;的几个关键特性：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;确保操作只执行一次&lt;/strong&gt;：无论有多少个goroutine调用&lt;code&gt;once.Do&lt;/code&gt;，操作都只会执行一次。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;线程安全&lt;/strong&gt;：&lt;code&gt;sync.Once&lt;/code&gt;是线程安全的，可以在多个goroutine中并发使用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;处理&lt;/strong&gt;**&lt;code&gt;panic&lt;/code&gt;**：即使在&lt;code&gt;once.Do&lt;/code&gt;中触发了&lt;code&gt;panic&lt;/code&gt;，&lt;code&gt;sync.Once&lt;/code&gt;也不会再次执行操作。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;希望通过这些示例，您能更好地理解和使用&lt;code&gt;sync.Once&lt;/code&gt;。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：使用原子操作和并发协调</title><link>https://blog.ithuo.net/posts/concurrency-coordination-in-go-with-atomic-operations/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/concurrency-coordination-in-go-with-atomic-operations/</guid><pubDate>Mon, 30 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在并发编程中，如何安全地共享和修改数据是一个重要的问题。Go语言提供了多种工具来帮助我们实现这一目标。本文将通过一个示例代码，详细讲解如何使用原子操作和并发协调工具（如通道和&lt;code&gt;sync.WaitGroup&lt;/code&gt;）来实现并发安全的操作。&lt;/p&gt;
&lt;h3&gt;示例代码解析&lt;/h3&gt;
&lt;p&gt;我们将通过以下两个示例来展示如何使用通道和&lt;code&gt;sync.WaitGroup&lt;/code&gt;来协调并发操作。&lt;/p&gt;
&lt;h3&gt;主函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func main() {
	coordinateWithChan()
	fmt.Println()
	coordinateWithWaitGroup()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;主函数调用了两个并发协调函数：&lt;code&gt;coordinateWithChan&lt;/code&gt;和&lt;code&gt;coordinateWithWaitGroup&lt;/code&gt;。我们将分别介绍这两个函数的实现。&lt;/p&gt;
&lt;h3&gt;使用通道进行并发协调&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func coordinateWithChan() {
	sign := make(chan struct{}, 2)
	num := int32(0)
	fmt.Printf(&quot;The number: %d [with chan struct{}]\\n&quot;, num)
	max := int32(10)
	go addNum(&amp;amp;num, 1, max, func() {
		sign &amp;lt;- struct{}{}
	})
	go addNum(&amp;amp;num, 2, max, func() {
		sign &amp;lt;- struct{}{}
	})
	&amp;lt;-sign
	&amp;lt;-sign
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个函数中，我们使用了一个带缓冲的通道&lt;code&gt;sign&lt;/code&gt;来协调两个并发操作。通道的缓冲大小为2，表示可以同时接收两个信号。我们启动了两个并发的&lt;code&gt;addNum&lt;/code&gt;函数，每个函数在完成后都会向通道发送一个信号。主函数通过接收两个信号来等待这两个并发操作的完成。&lt;/p&gt;
&lt;h3&gt;使用&lt;code&gt;sync.WaitGroup&lt;/code&gt;进行并发协调&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func coordinateWithWaitGroup() {
	var wg sync.WaitGroup
	wg.Add(2)
	num := int32(0)
	fmt.Printf(&quot;The number: %d [with sync.WaitGroup]\\n&quot;, num)
	max := int32(10)
	go addNum(&amp;amp;num, 3, max, wg.Done)
	go addNum(&amp;amp;num, 4, max, wg.Done)
	wg.Wait()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个函数中，我们使用了&lt;code&gt;sync.WaitGroup&lt;/code&gt;来协调并发操作。&lt;code&gt;WaitGroup&lt;/code&gt;的计数器初始值为2，表示有两个并发操作需要等待。每个并发的&lt;code&gt;addNum&lt;/code&gt;函数在完成后都会调用&lt;code&gt;wg.Done&lt;/code&gt;来减少计数器的值。主函数通过调用&lt;code&gt;wg.Wait&lt;/code&gt;来等待计数器变为0，从而等待所有并发操作的完成。&lt;/p&gt;
&lt;h3&gt;原子操作函数&lt;code&gt;addNum&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func addNum(numP *int32, id, max int32, deferFunc func()) {
	defer func() {
		deferFunc()
	}()
	for i := 0; ; i++ {
		currNum := atomic.LoadInt32(numP)
		if currNum &amp;gt;= max {
			break
		}
		newNum := currNum + 2
		time.Sleep(time.Millisecond * 200)
		if atomic.CompareAndSwapInt32(numP, currNum, newNum) {
			fmt.Printf(&quot;The number: %d [%d-%d]\\n&quot;, newNum, id, i)
		} else {
			fmt.Printf(&quot;The CAS operation failed. [%d-%d]\\n&quot;, id, i)
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;addNum&lt;/code&gt;函数用于原子地增加&lt;code&gt;numP&lt;/code&gt;所指向的变量的值。它使用了&lt;code&gt;atomic.LoadInt32&lt;/code&gt;和&lt;code&gt;atomic.CompareAndSwapInt32&lt;/code&gt;来确保操作的原子性。函数通过一个无限循环不断尝试增加&lt;code&gt;numP&lt;/code&gt;的值，直到达到&lt;code&gt;max&lt;/code&gt;。每次增加操作前，函数会先加载当前值，然后尝试将其增加2。如果&lt;code&gt;CompareAndSwapInt32&lt;/code&gt;操作成功，则表示增加操作成功；否则，表示在此期间值已被其他操作修改，增加操作失败。&lt;/p&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;通过以上示例，我们可以看到如何使用通道和&lt;code&gt;sync.WaitGroup&lt;/code&gt;来协调并发操作，以及如何使用原子操作来确保并发安全。以下是一些关键点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;通道&lt;/strong&gt;：通道可以用于在并发操作之间传递信号，从而实现简单的并发协调。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;sync.WaitGroup&lt;/code&gt;&lt;/strong&gt;：&lt;code&gt;WaitGroup&lt;/code&gt;可以用于等待一组并发操作的完成，是一种更灵活的并发协调工具。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;原子操作&lt;/strong&gt;：原子操作可以确保对共享变量的修改是并发安全的，避免数据竞争。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;希望通过这个教程，你能更好地理解和应用Go语言中的并发工具，编写出更加健壮的并发程序。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：深入浅出理解atomic.Value</title><link>https://blog.ithuo.net/posts/understanding-atomic-value-in-go-concurrency/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/understanding-atomic-value-in-go-concurrency/</guid><pubDate>Sun, 29 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在Go语言中，&lt;code&gt;atomic.Value&lt;/code&gt;是一个非常有用的工具，用于在并发编程中安全地存储和加载值。本文将通过一个示例代码，详细讲解&lt;code&gt;atomic.Value&lt;/code&gt;的使用方法和原理，并举一反三，帮助你更好地理解和应用。&lt;/p&gt;
&lt;h3&gt;示例代码解析&lt;/h3&gt;
&lt;p&gt;我们将通过以下几个示例来逐步解析&lt;code&gt;atomic.Value&lt;/code&gt;的使用。&lt;/p&gt;
&lt;h3&gt;示例1：基本使用&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;var box atomic.Value
fmt.Println(&quot;Copy box to box2.&quot;)
box2 := box // 原子值在真正使用前可以被复制。
v1 := [...]int{1, 2, 3}
fmt.Printf(&quot;Store %v to box.\\n&quot;, v1)
box.Store(v1)
fmt.Printf(&quot;The value load from box is %v.\\n&quot;, box.Load())
fmt.Printf(&quot;The value load from box2 is %v.\\n&quot;, box2.Load())
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个示例中，我们首先声明了一个&lt;code&gt;atomic.Value&lt;/code&gt;类型的变量&lt;code&gt;box&lt;/code&gt;。在存储值之前，我们可以安全地复制这个变量。然后，我们将一个数组存储到&lt;code&gt;box&lt;/code&gt;中，并从&lt;code&gt;box&lt;/code&gt;和&lt;code&gt;box2&lt;/code&gt;中加载值。&lt;/p&gt;
&lt;h3&gt;示例2：存储不同类型的值&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;v2 := &quot;123&quot;
fmt.Printf(&quot;Store %q to box2.\\n&quot;, v2)
box2.Store(v2) // 这里并不会引发panic。
fmt.Printf(&quot;The value load from box is %v.\\n&quot;, box.Load())
fmt.Printf(&quot;The value load from box2 is %q.\\n&quot;, box2.Load())
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个示例中，我们将一个字符串存储到&lt;code&gt;box2&lt;/code&gt;中。注意，&lt;code&gt;box2&lt;/code&gt;在存储值之前是可以存储任何类型的值的。&lt;/p&gt;
&lt;h3&gt;示例3：复制后的使用&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;fmt.Println(&quot;Copy box to box3.&quot;)
box3 := box // 原子值在真正使用后不应该被复制！
fmt.Printf(&quot;The value load from box3 is %v.\\n&quot;, box3.Load())
v3 := 123
fmt.Printf(&quot;Store %d to box3.\\n&quot;, v3)
//box3.Store(v3) // 这里会引发一个panic，报告存储值的类型不一致。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个示例中，我们展示了在存储值之后复制&lt;code&gt;atomic.Value&lt;/code&gt;变量会导致问题。&lt;code&gt;box3&lt;/code&gt;在存储值之后被复制，再次存储不同类型的值会引发panic。&lt;/p&gt;
&lt;h3&gt;示例4：存储实现相同接口的不同类型&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;var box4 atomic.Value
v4 := errors.New(&quot;something wrong&quot;)
fmt.Printf(&quot;Store an error with message %q to box4.\\n&quot;, v4)
box4.Store(v4)
v41 := io.EOF
fmt.Println(&quot;Store a value of the same type to box4.&quot;)
box4.Store(v41)
v42, ok := interface{}(&amp;amp;os.PathError{}).(error)
if ok {
    fmt.Printf(&quot;Store a value of type %T that implements error interface to box4.\\n&quot;, v42)
    //box4.Store(v42) // 这里会引发一个panic，报告存储值的类型不一致。
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个示例中，我们展示了如何存储实现相同接口的不同类型的值。注意，虽然&lt;code&gt;v42&lt;/code&gt;实现了&lt;code&gt;error&lt;/code&gt;接口，但它的具体类型与之前存储的值不同，因此会引发panic。&lt;/p&gt;
&lt;h3&gt;示例5：自定义atomicValue类型&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;box5, err := NewAtomicValue(v4)
if err != nil {
    fmt.Printf(&quot;error: %s\\n&quot;, err)
}
fmt.Printf(&quot;The legal type in box5 is %s.\\n&quot;, box5.TypeOfValue())
fmt.Println(&quot;Store a value of the same type to box5.&quot;)
err = box5.Store(v41)
if err != nil {
    fmt.Printf(&quot;error: %s\\n&quot;, err)
}
fmt.Printf(&quot;Store a value of type %T that implements error interface to box5.\\n&quot;, v42)
err = box5.Store(v42)
if err != nil {
    fmt.Printf(&quot;error: %s\\n&quot;, err)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个示例中，我们定义了一个自定义的&lt;code&gt;atomicValue&lt;/code&gt;类型，并通过构造函数&lt;code&gt;NewAtomicValue&lt;/code&gt;来初始化它。这个类型确保了存储的值类型一致性。&lt;/p&gt;
&lt;h3&gt;示例6：并发安全的存储&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;var box6 atomic.Value
v6 := []int{1, 2, 3}
fmt.Printf(&quot;Store %v to box6.\\n&quot;, v6)
box6.Store(v6)
v6[1] = 4 // 注意，此处的操作不是并发安全的！
fmt.Printf(&quot;The value load from box6 is %v.\\n&quot;, box6.Load())
// 正确的做法如下。
v6 = []int{1, 2, 3}
store := func(v []int) {
    replica := make([]int, len(v))
    copy(replica, v)
    box6.Store(replica)
}
fmt.Printf(&quot;Store %v to box6.\\n&quot;, v6)
store(v6)
v6[2] = 5 // 此处的操作是安全的。
fmt.Printf(&quot;The value load from box6 is %v.\\n&quot;, box6.Load())
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个示例中，我们展示了如何在并发环境中安全地存储和修改切片。直接修改存储的切片是不安全的，因此我们需要创建一个副本并存储它。&lt;/p&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;通过以上示例，我们可以看到&lt;code&gt;atomic.Value&lt;/code&gt;在并发编程中的重要性和使用方法。以下是一些关键点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;存储前可以复制&lt;/strong&gt;：在存储值之前，可以安全地复制&lt;code&gt;atomic.Value&lt;/code&gt;变量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;类型一致性&lt;/strong&gt;：存储的值类型必须一致，否则会引发panic。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;并发安全&lt;/strong&gt;：直接修改存储的值是不安全的，需要创建副本。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;希望通过这个教程，你能更好地理解和应用&lt;code&gt;atomic.Value&lt;/code&gt;，编写出更加健壮的并发程序。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：深入浅出原子操作与CAS</title><link>https://blog.ithuo.net/posts/go-tutorial-atomic-operations-and-cas/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-tutorial-atomic-operations-and-cas/</guid><pubDate>Sat, 28 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在本教程中，我们将通过一个示例代码来学习Go语言中的原子操作和CAS（Compare-And-Swap）机制。我们将逐步解析代码，深入理解其原理，并举一反三地探讨其应用。&lt;/p&gt;
&lt;h3&gt;1. 原子操作简介&lt;/h3&gt;
&lt;p&gt;原子操作是指不可分割的操作，即在执行过程中不会被中断。Go语言提供了一些原子操作函数，主要用于多线程环境下的并发控制，确保数据的一致性和安全性。&lt;/p&gt;
&lt;h3&gt;2. 示例代码解析&lt;/h3&gt;
&lt;h3&gt;2.1 基本的原子加法操作&lt;/h3&gt;
&lt;p&gt;首先，我们来看一个简单的原子加法操作示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;fmt&quot;
	&quot;sync/atomic&quot;
)

func main() {
	num := uint32(18)
	fmt.Printf(&quot;The number: %d\\n&quot;, num)
	delta := int32(-3)
	atomic.AddUint32(&amp;amp;num, uint32(delta))
	fmt.Printf(&quot;The number: %d\\n&quot;, num)
	atomic.AddUint32(&amp;amp;num, ^uint32(-(-3)-1))
	fmt.Printf(&quot;The number: %d\\n&quot;, num)

	fmt.Printf(&quot;The two&apos;s complement of %d: %b\\n&quot;, delta, uint32(delta))
	fmt.Printf(&quot;The equivalent: %b\\n&quot;, ^uint32(-(-3)-1))
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个示例中，我们使用了&lt;code&gt;atomic.AddUint32&lt;/code&gt;函数来进行原子加法操作。需要注意的是，&lt;code&gt;atomic.AddUint32&lt;/code&gt;的第二个参数必须是无符号整数，因此我们需要进行类型转换。&lt;/p&gt;
&lt;h3&gt;2.2 自旋锁示例&lt;/h3&gt;
&lt;p&gt;接下来，我们来看一个使用自旋锁的示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func forAndCAS1() {
	sign := make(chan struct{}, 2)
	num := int32(0)
	fmt.Printf(&quot;The number: %d\\n&quot;, num)
	go func() {
		defer func() {
			sign &amp;lt;- struct{}{}
		}()
		for {
			time.Sleep(time.Millisecond * 500)
			newNum := atomic.AddInt32(&amp;amp;num, 2)
			fmt.Printf(&quot;The number: %d\\n&quot;, newNum)
			if newNum == 10 {
				break
			}
		}
	}()
	go func() {
		defer func() {
			sign &amp;lt;- struct{}{}
		}()
		for {
			if atomic.CompareAndSwapInt32(&amp;amp;num, 10, 0) {
				fmt.Println(&quot;The number has gone to zero.&quot;)
				break
			}
			time.Sleep(time.Millisecond * 500)
		}
	}()
	&amp;lt;-sign
	&amp;lt;-sign
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个示例中，我们使用了&lt;code&gt;atomic.AddInt32&lt;/code&gt;和&lt;code&gt;atomic.CompareAndSwapInt32&lt;/code&gt;函数来实现一个简易的自旋锁。自旋锁是一种忙等待的锁机制，线程在等待锁释放时会不断地检查锁的状态。&lt;/p&gt;
&lt;h3&gt;2.3 互斥锁示例&lt;/h3&gt;
&lt;p&gt;最后，我们来看一个模拟互斥锁的示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func forAndCAS2() {
	sign := make(chan struct{}, 2)
	num := int32(0)
	fmt.Printf(&quot;The number: %d\\n&quot;, num)
	max := int32(20)
	go func(id int, max int32) {
		defer func() {
			sign &amp;lt;- struct{}{}
		}()
		for i := 0; ; i++ {
			currNum := atomic.LoadInt32(&amp;amp;num)
			if currNum &amp;gt;= max {
				break
			}
			newNum := currNum + 2
			time.Sleep(time.Millisecond * 200)
			if atomic.CompareAndSwapInt32(&amp;amp;num, currNum, newNum) {
				fmt.Printf(&quot;The number: %d [%d-%d]\\n&quot;, newNum, id, i)
			} else {
				fmt.Printf(&quot;The CAS operation failed. [%d-%d]\\n&quot;, id, i)
			}
		}
	}(1, max)
	go func(id int, max int32) {
		defer func() {
			sign &amp;lt;- struct{}{}
		}()
		for j := 0; ; j++ {
			currNum := atomic.LoadInt32(&amp;amp;num)
			if currNum &amp;gt;= max {
				break
			}
			newNum := currNum + 2
			time.Sleep(time.Millisecond * 200)
			if atomic.CompareAndSwapInt32(&amp;amp;num, currNum, newNum) {
				fmt.Printf(&quot;The number: %d [%d-%d]\\n&quot;, newNum, id, j)
			} else {
				fmt.Printf(&quot;The CAS operation failed. [%d-%d]\\n&quot;, id, j)
			}
		}
	}(2, max)
	&amp;lt;-sign
	&amp;lt;-sign
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个示例中，我们使用了&lt;code&gt;atomic.LoadInt32&lt;/code&gt;和&lt;code&gt;atomic.CompareAndSwapInt32&lt;/code&gt;函数来模拟一个宽松的互斥锁。互斥锁用于保护共享资源，确保同一时间只有一个线程可以访问该资源。&lt;/p&gt;
&lt;h3&gt;3. 原理解析&lt;/h3&gt;
&lt;h3&gt;3.1 原子操作的实现&lt;/h3&gt;
&lt;p&gt;原子操作通过硬件支持的指令实现，确保操作的不可分割性。在多核处理器中，原子操作可以避免竞态条件，确保数据的一致性。&lt;/p&gt;
&lt;h3&gt;3.2 CAS机制&lt;/h3&gt;
&lt;p&gt;CAS（Compare-And-Swap）是一种常见的原子操作，用于实现无锁编程。CAS操作会比较内存中的值与预期值，如果相等则更新为新值，否则不做任何操作。CAS操作的核心在于其原子性，确保比较和交换操作在一个不可分割的步骤中完成。&lt;/p&gt;
&lt;h3&gt;4. 举一反三&lt;/h3&gt;
&lt;p&gt;通过上述示例，我们可以看到原子操作和CAS机制在并发编程中的重要性。我们可以将这些技术应用到更多的场景中，例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;实现无锁队列&lt;/li&gt;
&lt;li&gt;实现无锁计数器&lt;/li&gt;
&lt;li&gt;实现高效的并发数据结构&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;5. 总结&lt;/h3&gt;
&lt;p&gt;在本教程中，我们通过示例代码深入浅出地介绍了Go语言中的原子操作和CAS机制。我们不仅理解了其基本原理，还通过实际应用场景加深了对这些技术的理解。希望通过本教程，您能够更好地掌握Go语言中的并发编程技巧。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：使用条件变量实现信箱模型 2</title><link>https://blog.ithuo.net/posts/go-concurrency-using-condition-variables-mailbox-model/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-concurrency-using-condition-variables-mailbox-model/</guid><pubDate>Fri, 27 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在本教程中，我们将深入探讨如何使用Go语言中的条件变量（&lt;code&gt;sync.Cond&lt;/code&gt;）来实现一个简单的信箱模型。这个模型模拟了发送和接收信件的过程，确保在信箱为空时不能发送信件，在信箱为满时不能接收信件。&lt;/p&gt;
&lt;h3&gt;代码概述&lt;/h3&gt;
&lt;p&gt;我们将从以下几个方面来讲解代码：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;信箱和锁的定义&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;条件变量的创建&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;发送和接收函数的实现&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;并发发送和接收的实现&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;主函数的执行流程&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;1. 信箱和锁的定义&lt;/h3&gt;
&lt;p&gt;首先，我们定义了一个信箱和一个互斥锁：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var mailbox uint8
var lock sync.Mutex
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mailbox&lt;/code&gt; 代表信箱的状态，&lt;code&gt;0&lt;/code&gt;表示空，&lt;code&gt;1&lt;/code&gt;表示满。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lock&lt;/code&gt; 是一个互斥锁，用于保护对信箱状态的并发访问。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 条件变量的创建&lt;/h3&gt;
&lt;p&gt;接下来，我们创建了两个条件变量：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sendCond := sync.NewCond(&amp;amp;lock)
recvCond := sync.NewCond(&amp;amp;lock)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sendCond&lt;/code&gt; 用于发送信件的条件变量。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;recvCond&lt;/code&gt; 用于接收信件的条件变量。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. 发送和接收函数的实现&lt;/h3&gt;
&lt;h3&gt;发送函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;send := func(id, index int) {
    lock.Lock()
    for mailbox == 1 {
        sendCond.Wait()
    }
    log.Printf(&quot;sender [%d-%d]: the mailbox is empty.&quot;, id, index)
    mailbox = 1
    log.Printf(&quot;sender [%d-%d]: the letter has been sent.&quot;, id, index)
    lock.Unlock()
    recvCond.Broadcast()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;先获取锁，检查信箱是否满。&lt;/li&gt;
&lt;li&gt;如果信箱满，则等待条件变量&lt;code&gt;sendCond&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;信箱为空时，发送信件并设置信箱状态为满。&lt;/li&gt;
&lt;li&gt;释放锁并通知所有等待接收信件的goroutine。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;接收函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;recv := func(id, index int) {
    lock.Lock()
    for mailbox == 0 {
        recvCond.Wait()
    }
    log.Printf(&quot;receiver [%d-%d]: the mailbox is full.&quot;, id, index)
    mailbox = 0
    log.Printf(&quot;receiver [%d-%d]: the letter has been received.&quot;, id, index)
    lock.Unlock()
    sendCond.Signal()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;先获取锁，检查信箱是否空。&lt;/li&gt;
&lt;li&gt;如果信箱空，则等待条件变量&lt;code&gt;recvCond&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;信箱为满时，接收信件并设置信箱状态为空。&lt;/li&gt;
&lt;li&gt;释放锁并通知一个等待发送信件的goroutine。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4. 并发发送和接收的实现&lt;/h3&gt;
&lt;p&gt;我们使用goroutine来并发地发送和接收信件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sign := make(chan struct{}, 3)
max := 6

go func(id, max int) {
    defer func() { sign &amp;lt;- struct{}{} }()
    for i := 1; i &amp;lt;= max; i++ {
        time.Sleep(time.Millisecond * 500)
        send(id, i)
    }
}(0, max)

go func(id, max int) {
    defer func() { sign &amp;lt;- struct{}{} }()
    for j := 1; j &amp;lt;= max; j++ {
        time.Sleep(time.Millisecond * 200)
        recv(id, j)
    }
}(1, max/2)

go func(id, max int) {
    defer func() { sign &amp;lt;- struct{}{} }()
    for k := 1; k &amp;lt;= max; k++ {
        time.Sleep(time.Millisecond * 200)
        recv(id, k)
    }
}(2, max/2)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;我们启动了三个goroutine：一个用于发送信件，两个用于接收信件。&lt;/li&gt;
&lt;li&gt;每个goroutine在完成任务后向&lt;code&gt;sign&lt;/code&gt;通道发送信号，表示任务完成。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;5. 主函数的执行流程&lt;/h3&gt;
&lt;p&gt;主函数等待所有goroutine完成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;-sign
&amp;lt;-sign
&amp;lt;-sign
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;主函数通过接收&lt;code&gt;sign&lt;/code&gt;通道的信号来等待所有goroutine完成。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;通过这个示例，我们学习了如何使用Go语言中的条件变量来实现一个简单的信箱模型。我们使用互斥锁保护共享资源，并通过条件变量实现了发送和接收信件的同步机制。&lt;/p&gt;
&lt;h3&gt;举一反三&lt;/h3&gt;
&lt;p&gt;在实际应用中，条件变量可以用于解决各种并发控制问题，例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;生产者-消费者模型&lt;/li&gt;
&lt;li&gt;资源池管理&lt;/li&gt;
&lt;li&gt;复杂的同步逻辑&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;希望通过这个教程，您能更好地理解Go语言中的条件变量，并能将其应用到实际项目中。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：使用条件变量实现信箱模型</title><link>https://blog.ithuo.net/posts/go-concurrency-mailbox-model-tutorial/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-concurrency-mailbox-model-tutorial/</guid><pubDate>Thu, 26 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在本教程中，我们将通过一个简单的信箱模型来学习Go语言中的条件变量（Condition Variable）和互斥锁（Mutex）。这个模型模拟了一个信箱的发送和接收过程，信箱可以是空的或满的。我们将详细解释代码的每一部分，并举一反三，帮助你更好地理解这些概念。&lt;/p&gt;
&lt;h3&gt;代码概述&lt;/h3&gt;
&lt;p&gt;以下是我们将要分析的Go代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;log&quot;
	&quot;sync&quot;
	&quot;time&quot;
)

func main() {
	// mailbox 代表信箱。
	// 0代表信箱是空的，1代表信箱是满的。
	var mailbox uint8
	// lock 代表信箱上的锁。
	var lock sync.RWMutex
	// sendCond 代表专用于发信的条件变量。
	sendCond := sync.NewCond(&amp;amp;lock)
	// recvCond 代表专用于收信的条件变量。
	recvCond := sync.NewCond(lock.RLocker())

	// sign 用于传递演示完成的信号。
	sign := make(chan struct{}, 3)
	max := 5
	go func(max int) { // 用于发信。
		defer func() {
			sign &amp;lt;- struct{}{}
		}()
		for i := 1; i &amp;lt;= max; i++ {
			time.Sleep(time.Millisecond * 500)
			lock.Lock()
			for mailbox == 1 {
				sendCond.Wait()
			}
			log.Printf(&quot;sender [%d]: the mailbox is empty.&quot;, i)
			mailbox = 1
			log.Printf(&quot;sender [%d]: the letter has been sent.&quot;, i)
			lock.Unlock()
			recvCond.Signal()
		}
	}(max)
	go func(max int) { // 用于收信。
		defer func() {
			sign &amp;lt;- struct{}{}
		}()
		for j := 1; j &amp;lt;= max; j++ {
			time.Sleep(time.Millisecond * 500)
			lock.RLock()
			for mailbox == 0 {
				recvCond.Wait()
			}
			log.Printf(&quot;receiver [%d]: the mailbox is full.&quot;, j)
			mailbox = 0
			log.Printf(&quot;receiver [%d]: the letter has been received.&quot;, j)
			lock.RUnlock()
			sendCond.Signal()
		}
	}(max)

	&amp;lt;-sign
	&amp;lt;-sign
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;代码详解&lt;/h3&gt;
&lt;h3&gt;1. 变量声明&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;var mailbox uint8
var lock sync.RWMutex
sendCond := sync.NewCond(&amp;amp;lock)
recvCond := sync.NewCond(lock.RLocker())
sign := make(chan struct{}, 3)
max := 5
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mailbox&lt;/code&gt;：表示信箱的状态，0表示空，1表示满。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lock&lt;/code&gt;：读写锁，用于保护对&lt;code&gt;mailbox&lt;/code&gt;的访问。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sendCond&lt;/code&gt;：用于发送信的条件变量。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;recvCond&lt;/code&gt;：用于接收信的条件变量。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sign&lt;/code&gt;：用于传递演示完成的信号。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;max&lt;/code&gt;：表示发送和接收的最大次数。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 发信协程&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;go func(max int) {
	defer func() {
		sign &amp;lt;- struct{}{}
	}()
	for i := 1; i &amp;lt;= max; i++ {
		time.Sleep(time.Millisecond * 500)
		lock.Lock()
		for mailbox == 1 {
			sendCond.Wait()
		}
		log.Printf(&quot;sender [%d]: the mailbox is empty.&quot;, i)
		mailbox = 1
		log.Printf(&quot;sender [%d]: the letter has been sent.&quot;, i)
		lock.Unlock()
		recvCond.Signal()
	}
}(max)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;使用&lt;code&gt;lock.Lock()&lt;/code&gt;加锁，确保对&lt;code&gt;mailbox&lt;/code&gt;的访问是线程安全的。&lt;/li&gt;
&lt;li&gt;如果&lt;code&gt;mailbox&lt;/code&gt;是满的（&lt;code&gt;mailbox == 1&lt;/code&gt;），则调用&lt;code&gt;sendCond.Wait()&lt;/code&gt;等待。&lt;/li&gt;
&lt;li&gt;当信箱为空时，发送信件（将&lt;code&gt;mailbox&lt;/code&gt;设为1），并解锁。&lt;/li&gt;
&lt;li&gt;使用&lt;code&gt;recvCond.Signal()&lt;/code&gt;通知接收协程信箱已满。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. 收信协程&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;go func(max int) {
	defer func() {
		sign &amp;lt;- struct{}{}
	}()
	for j := 1; j &amp;lt;= max; j++ {
		time.Sleep(time.Millisecond * 500)
		lock.RLock()
		for mailbox == 0 {
			recvCond.Wait()
		}
		log.Printf(&quot;receiver [%d]: the mailbox is full.&quot;, j)
		mailbox = 0
		log.Printf(&quot;receiver [%d]: the letter has been received.&quot;, j)
		lock.RUnlock()
		sendCond.Signal()
	}
}(max)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;使用&lt;code&gt;lock.RLock()&lt;/code&gt;加锁，确保对&lt;code&gt;mailbox&lt;/code&gt;的访问是线程安全的。&lt;/li&gt;
&lt;li&gt;如果&lt;code&gt;mailbox&lt;/code&gt;是空的（&lt;code&gt;mailbox == 0&lt;/code&gt;），则调用&lt;code&gt;recvCond.Wait()&lt;/code&gt;等待。&lt;/li&gt;
&lt;li&gt;当信箱满时，接收信件（将&lt;code&gt;mailbox&lt;/code&gt;设为0），并解锁。&lt;/li&gt;
&lt;li&gt;使用&lt;code&gt;sendCond.Signal()&lt;/code&gt;通知发送协程信箱已空。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4. 等待协程完成&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;-sign
&amp;lt;-sign
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;等待两个协程完成。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;举一反三&lt;/h3&gt;
&lt;h3&gt;1. 多个发送者和接收者&lt;/h3&gt;
&lt;p&gt;可以扩展代码，使其支持多个发送者和接收者。只需启动多个发送和接收协程，并适当调整条件变量的使用。&lt;/p&gt;
&lt;h3&gt;2. 使用通道（Channel）&lt;/h3&gt;
&lt;p&gt;Go语言中的通道（Channel）可以简化这种生产者-消费者模型。以下是使用通道实现的示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;log&quot;
	&quot;time&quot;
)

func main() {
	mailbox := make(chan struct{}, 1)
	sign := make(chan struct{}, 2)
	max := 5

	go func(max int) {
		defer func() {
			sign &amp;lt;- struct{}{}
		}()
		for i := 1; i &amp;lt;= max; i++ {
			time.Sleep(time.Millisecond * 500)
			mailbox &amp;lt;- struct{}{}
			log.Printf(&quot;sender [%d]: the letter has been sent.&quot;, i)
		}
	}(max)

	go func(max int) {
		defer func() {
			sign &amp;lt;- struct{}{}
		}()
		for j := 1; j &amp;lt;= max; j++ {
			time.Sleep(time.Millisecond * 500)
			&amp;lt;-mailbox
			log.Printf(&quot;receiver [%d]: the letter has been received.&quot;, j)
		}
	}(max)

	&amp;lt;-sign
	&amp;lt;-sign
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;通过这个教程，我们学习了如何使用Go语言中的条件变量和互斥锁来实现一个简单的信箱模型。我们还展示了如何使用通道来简化这种生产者-消费者模型。希望这个教程能帮助你更好地理解Go语言中的并发编程。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：使用读写锁实现并发安全的计数器</title><link>https://blog.ithuo.net/posts/concurrent-safe-counter-using-rwmutex-in-golang/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/concurrent-safe-counter-using-rwmutex-in-golang/</guid><pubDate>Wed, 25 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在本教程中，我们将通过一个简单的计数器示例，学习如何使用Go语言中的读写锁（&lt;code&gt;sync.RWMutex&lt;/code&gt;）来实现并发安全的操作。我们将详细解释代码的每一部分，并提供一些额外的示例来帮助你更好地理解。&lt;/p&gt;
&lt;h3&gt;代码结构&lt;/h3&gt;
&lt;p&gt;首先，让我们看一下完整的代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;log&quot;
	&quot;sync&quot;
	&quot;time&quot;
)

// counter 代表计数器。
type counter struct {
	num uint         // 计数。
	mu  sync.RWMutex // 读写锁。
}

// number 会返回当前的计数。
func (c *counter) number() uint {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.num
}

// add 会增加计数器的值，并会返回增加后的计数。
func (c *counter) add(increment uint) uint {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.num += increment
	return c.num
}

func main() {
	c := counter{}
	count(&amp;amp;c)
	redundantUnlock()
}

func count(c *counter) {
	// sign 用于传递演示完成的信号。
	sign := make(chan struct{}, 3)
	go func() { // 用于增加计数。
		defer func() {
			sign &amp;lt;- struct{}{}
		}()
		for i := 1; i &amp;lt;= 10; i++ {
			time.Sleep(time.Millisecond * 500)
			c.add(1)
		}
	}()
	go func() {
		defer func() {
			sign &amp;lt;- struct{}{}
		}()
		for j := 1; j &amp;lt;= 20; j++ {
			time.Sleep(time.Millisecond * 200)
			log.Printf(&quot;The number in counter: %d [%d-%d]&quot;,
				c.number(), 1, j)
		}
	}()
	go func() {
		defer func() {
			sign &amp;lt;- struct{}{}
		}()
		for k := 1; k &amp;lt;= 20; k++ {
			time.Sleep(time.Millisecond * 300)
			log.Printf(&quot;The number in counter: %d [%d-%d]&quot;,
				c.number(), 2, k)
		}
	}()
	&amp;lt;-sign
	&amp;lt;-sign
	&amp;lt;-sign
}

func redundantUnlock() {
	var rwMu sync.RWMutex

	// 示例1。
	//rwMu.Unlock() // 这里会引发panic。

	// 示例2。
	//rwMu.RUnlock() // 这里会引发panic。

	// 示例3。
	rwMu.RLock()
	//rwMu.Unlock() // 这里会引发panic。
	rwMu.RUnlock()

	// 示例4。
	rwMu.Lock()
	//rwMu.RUnlock() // 这里会引发panic。
	rwMu.Unlock()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;代码解析&lt;/h3&gt;
&lt;h3&gt;1. 定义计数器结构体&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;type counter struct {
	num uint         // 计数。
	mu  sync.RWMutex // 读写锁。
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;counter&lt;/code&gt;结构体包含一个无符号整数&lt;code&gt;num&lt;/code&gt;用于存储计数值，以及一个读写锁&lt;code&gt;mu&lt;/code&gt;用于保护对&lt;code&gt;num&lt;/code&gt;的并发访问。&lt;/p&gt;
&lt;h3&gt;2. 获取当前计数值的方法&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func (c *counter) number() uint {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.num
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;number&lt;/code&gt;方法使用读锁（&lt;code&gt;RLock&lt;/code&gt;）来保护对&lt;code&gt;num&lt;/code&gt;的读取操作，并在读取完成后释放读锁（&lt;code&gt;RUnlock&lt;/code&gt;）。&lt;/p&gt;
&lt;h3&gt;3. 增加计数值的方法&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func (c *counter) add(increment uint) uint {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.num += increment
	return c.num
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;add&lt;/code&gt;方法使用写锁（&lt;code&gt;Lock&lt;/code&gt;）来保护对&lt;code&gt;num&lt;/code&gt;的写操作，并在写入完成后释放写锁（&lt;code&gt;Unlock&lt;/code&gt;）。&lt;/p&gt;
&lt;h3&gt;4. 主函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func main() {
	c := counter{}
	count(&amp;amp;c)
	redundantUnlock()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在&lt;code&gt;main&lt;/code&gt;函数中，我们创建一个&lt;code&gt;counter&lt;/code&gt;实例，并调用&lt;code&gt;count&lt;/code&gt;函数和&lt;code&gt;redundantUnlock&lt;/code&gt;函数。&lt;/p&gt;
&lt;h3&gt;5. 并发计数函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func count(c *counter) {
	// sign 用于传递演示完成的信号。
	sign := make(chan struct{}, 3)
	go func() { // 用于增加计数。
		defer func() {
			sign &amp;lt;- struct{}{}
		}()
		for i := 1; i &amp;lt;= 10; i++ {
			time.Sleep(time.Millisecond * 500)
			c.add(1)
		}
	}()
	go func() {
		defer func() {
			sign &amp;lt;- struct{}{}
		}()
		for j := 1; j &amp;lt;= 20; j++ {
			time.Sleep(time.Millisecond * 200)
			log.Printf(&quot;The number in counter: %d [%d-%d]&quot;,
				c.number(), 1, j)
		}
	}()
	go func() {
		defer func() {
			sign &amp;lt;- struct{}{}
		}()
		for k := 1; k &amp;lt;= 20; k++ {
			time.Sleep(time.Millisecond * 300)
			log.Printf(&quot;The number in counter: %d [%d-%d]&quot;,
				c.number(), 2, k)
		}
	}()
	&amp;lt;-sign
	&amp;lt;-sign
	&amp;lt;-sign
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;count&lt;/code&gt;函数启动了三个并发的goroutine：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一个goroutine每500毫秒增加一次计数。&lt;/li&gt;
&lt;li&gt;第二个和第三个goroutine分别每200毫秒和300毫秒读取并打印当前计数值。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;sign&lt;/code&gt;通道用于等待所有goroutine完成。&lt;/p&gt;
&lt;h3&gt;6. 错误解锁示例&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func redundantUnlock() {
	var rwMu sync.RWMutex

	// 示例1。
	//rwMu.Unlock() // 这里会引发panic。

	// 示例2。
	//rwMu.RUnlock() // 这里会引发panic。

	// 示例3。
	rwMu.RLock()
	//rwMu.Unlock() // 这里会引发panic。
	rwMu.RUnlock()

	// 示例4。
	rwMu.Lock()
	//rwMu.RUnlock() // 这里会引发panic。
	rwMu.Unlock()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;redundantUnlock&lt;/code&gt;函数展示了几种错误使用读写锁的方法，这些错误会导致程序崩溃（panic）。正确的使用方式是成对调用&lt;code&gt;RLock&lt;/code&gt;/&lt;code&gt;RUnlock&lt;/code&gt;和&lt;code&gt;Lock&lt;/code&gt;/&lt;code&gt;Unlock&lt;/code&gt;。&lt;/p&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;通过这个示例，我们学习了如何使用Go语言中的读写锁来实现并发安全的计数器。我们还展示了几种错误使用锁的方法，以帮助你避免常见的陷阱。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：并发处理与同步机制</title><link>https://blog.ithuo.net/posts/go-concurrency-and-synchronization-tutorial/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-concurrency-and-synchronization-tutorial/</guid><pubDate>Tue, 24 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;本文将通过一个示例代码，深入浅出地介绍Go语言中的并发处理与同步机制。我们将逐步解析代码，帮助你理解其原理，并举一反三地应用到其他场景中。&lt;/p&gt;
&lt;h3&gt;示例代码概述&lt;/h3&gt;
&lt;p&gt;该示例代码展示了如何使用Go语言的goroutine和通道（channel）来实现并发处理。代码中定义了一个数据处理配置结构体&lt;code&gt;handlerConfig&lt;/code&gt;，并通过多个goroutine对缓冲区进行数据的并发写入和读取。&lt;/p&gt;
&lt;h3&gt;代码解析&lt;/h3&gt;
&lt;h3&gt;1. 导入必要的包&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;import (
	&quot;bytes&quot;
	&quot;errors&quot;
	&quot;fmt&quot;
	&quot;io&quot;
	&quot;log&quot;
	&quot;sync&quot;
	&quot;time&quot;
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些包提供了我们需要的基本功能，如输入输出操作、错误处理、日志记录、并发控制等。&lt;/p&gt;
&lt;h3&gt;2. 定义处理函数类型和配置结构体&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;type singleHandler func() (data string, n int, err error)

type handlerConfig struct {
	handler   singleHandler
	goNum     int
	number    int
	interval  time.Duration
	counter   int
	counterMu sync.Mutex
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;singleHandler&lt;/code&gt;：定义了一个处理函数类型，返回处理的数据、数据长度和错误信息。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;handlerConfig&lt;/code&gt;：定义了处理配置，包括处理函数、goroutine数量、处理次数、间隔时间、计数器和计数器的互斥锁。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. 计数器方法&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func (hc *handlerConfig) count(increment int) int {
	hc.counterMu.Lock()
	defer hc.counterMu.Unlock()
	hc.counter += increment
	return hc.counter
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;count&lt;/code&gt;方法用于安全地增加计数器的值，并返回增加后的计数。使用互斥锁&lt;code&gt;counterMu&lt;/code&gt;来确保线程安全。&lt;/p&gt;
&lt;h3&gt;4. 主函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func main() {
	var mu sync.Mutex

	genWriter := func(writer io.Writer) singleHandler {
		return func() (data string, n int, err error) {
			data = fmt.Sprintf(&quot;%s\\t&quot;, time.Now().Format(time.StampNano))
			mu.Lock()
			defer mu.Unlock()
			n, err = writer.Write([]byte(data))
			return
		}
	}

	genReader := func(reader io.Reader) singleHandler {
		return func() (data string, n int, err error) {
			buffer, ok := reader.(*bytes.Buffer)
			if !ok {
				err = errors.New(&quot;unsupported reader&quot;)
				return
			}
			mu.Lock()
			defer mu.Unlock()
			data, err = buffer.ReadString(&apos;\\t&apos;)
			n = len(data)
			return
		}
	}

	var buffer bytes.Buffer

	writingConfig := handlerConfig{
		handler:  genWriter(&amp;amp;buffer),
		goNum:    5,
		number:   4,
		interval: time.Millisecond * 100,
	}

	readingConfig := handlerConfig{
		handler:  genReader(&amp;amp;buffer),
		goNum:    10,
		number:   2,
		interval: time.Millisecond * 100,
	}

	sign := make(chan struct{}, writingConfig.goNum+readingConfig.goNum)

	for i := 1; i &amp;lt;= writingConfig.goNum; i++ {
		go func(i int) {
			defer func() { sign &amp;lt;- struct{}{} }()
			for j := 1; j &amp;lt;= writingConfig.number; j++ {
				time.Sleep(writingConfig.interval)
				data, n, err := writingConfig.handler()
				if err != nil {
					log.Printf(&quot;writer [%d-%d]: error: %s&quot;, i, j, err)
					continue
				}
				total := writingConfig.count(n)
				log.Printf(&quot;writer [%d-%d]: %s (total: %d)&quot;, i, j, data, total)
			}
		}(i)
	}

	for i := 1; i &amp;lt;= readingConfig.goNum; i++ {
		go func(i int) {
			defer func() { sign &amp;lt;- struct{}{} }()
			for j := 1; j &amp;lt;= readingConfig.number; j++ {
				time.Sleep(readingConfig.interval)
				var data string
				var n int
				var err error
				for {
					data, n, err = readingConfig.handler()
					if err == nil || err != io.EOF {
						break
					}
					time.Sleep(readingConfig.interval)
				}
				if err != nil {
					log.Printf(&quot;reader [%d-%d]: error: %s&quot;, i, j, err)
					continue
				}
				total := readingConfig.count(n)
				log.Printf(&quot;reader [%d-%d]: %s (total: %d)&quot;, i, j, data, total)
			}
		}(i)
	}

	signNumber := writingConfig.goNum + readingConfig.goNum
	for j := 0; j &amp;lt; signNumber; j++ {
		&amp;lt;-sign
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5. 生成写入和读取函数&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;genWriter&lt;/code&gt;：生成一个写入函数，向缓冲区写入当前时间戳。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;genReader&lt;/code&gt;：生成一个读取函数，从缓冲区读取数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;6. 配置写入和读取&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;writingConfig&lt;/code&gt;：配置写入操作，包括处理函数、goroutine数量、处理次数和间隔时间。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;readingConfig&lt;/code&gt;：配置读取操作。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;7. 启动goroutine进行并发处理&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;启动多个goroutine进行数据写入，每个goroutine按照配置的次数和间隔时间进行操作。&lt;/li&gt;
&lt;li&gt;启动多个goroutine进行数据读取，处理读取过程中可能出现的EOF错误。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;8. 等待所有goroutine完成&lt;/h3&gt;
&lt;p&gt;使用通道&lt;code&gt;sign&lt;/code&gt;来等待所有goroutine完成操作。&lt;/p&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;通过这个示例代码，我们学习了如何在Go语言中使用goroutine和通道来实现并发处理，并通过互斥锁确保数据的线程安全。你可以将这种模式应用到其他需要并发处理的场景中，如并发网络请求、并发文件处理等。&lt;/p&gt;
&lt;p&gt;希望这个教程对你有所帮助！如果有任何问题，欢迎随时提问。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：并发与互斥锁</title><link>https://blog.ithuo.net/posts/go-concurrency-and-mutex-tutorial/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-concurrency-and-mutex-tutorial/</guid><pubDate>Mon, 23 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;本文将通过一个示例代码，详细讲解Go语言中的并发编程和互斥锁的使用。示例代码展示了如何使用goroutine进行并发操作，以及如何使用互斥锁保护共享资源。&lt;/p&gt;
&lt;h2&gt;示例代码解析&lt;/h2&gt;
&lt;h3&gt;导入包&lt;/h3&gt;
&lt;p&gt;首先，我们需要导入一些必要的包：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import (
	&quot;bytes&quot;
	&quot;flag&quot;
	&quot;fmt&quot;
	&quot;io&quot;
	&quot;io/ioutil&quot;
	&quot;log&quot;
	&quot;sync&quot;
)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bytes&lt;/code&gt;：提供了缓冲区操作。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;flag&lt;/code&gt;：用于解析命令行参数。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fmt&lt;/code&gt;：格式化I/O。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;io&lt;/code&gt;：基本的I/O接口。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ioutil&lt;/code&gt;：I/O工具函数。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;log&lt;/code&gt;：日志记录。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sync&lt;/code&gt;：并发原语，包括互斥锁。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;全局变量&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;var protecting uint
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;protecting&lt;/code&gt;变量用于指示是否使用互斥锁来保护数据写入。值为0表示不使用，值大于0表示使用。&lt;/p&gt;
&lt;h3&gt;初始化函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func init() {
	flag.UintVar(&amp;amp;protecting, &quot;protecting&quot;, 1, &quot;It indicates whether to use a mutex to protect data writing.&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;init&lt;/code&gt;函数用于初始化命令行参数&lt;code&gt;protecting&lt;/code&gt;，默认值为1。&lt;/p&gt;
&lt;h3&gt;主函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func main() {
	flag.Parse()
	var buffer bytes.Buffer

	const (
		max1 = 5  // 启用的goroutine数量
		max2 = 10 // 每个goroutine写入的数据块数量
		max3 = 10 // 每个数据块中重复的数字数量
	)

	var mu sync.Mutex
	sign := make(chan struct{}, max1)

	for i := 1; i &amp;lt;= max1; i++ {
		go func(id int, writer io.Writer) {
			defer func() {
				sign &amp;lt;- struct{}{}
			}()
			for j := 1; j &amp;lt;= max2; j++ {
				header := fmt.Sprintf(&quot;\\n[id: %d, iteration: %d]&quot;, id, j)
				data := fmt.Sprintf(&quot; %d&quot;, id*j)
				if protecting &amp;gt; 0 {
					mu.Lock()
				}
				_, err := writer.Write([]byte(header))
				if err != nil {
					log.Printf(&quot;error: %s [%d]&quot;, err, id)
				}
				for k := 0; k &amp;lt; max3; k++ {
					_, err := writer.Write([]byte(data))
					if err != nil {
						log.Printf(&quot;error: %s [%d]&quot;, err, id)
					}
				}
				if protecting &amp;gt; 0 {
					mu.Unlock()
				}
			}
		}(i, &amp;amp;buffer)
	}

	for i := 0; i &amp;lt; max1; i++ {
		&amp;lt;-sign
	}
	data, err := ioutil.ReadAll(&amp;amp;buffer)
	if err != nil {
		log.Fatalf(&quot;fatal error: %s&quot;, err)
	}
	log.Printf(&quot;The contents:\\n%s&quot;, data)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;代码详解&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;解析命令行参数&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;flag.Parse()
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;定义缓冲区&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var buffer bytes.Buffer
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;常量定义&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const (
    max1 = 5  // 启用的goroutine数量
    max2 = 10 // 每个goroutine写入的数据块数量
    max3 = 10 // 每个数据块中重复的数字数量
)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;互斥锁和信号通道&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var mu sync.Mutex
sign := make(chan struct{}, max1)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;启动goroutine&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for i := 1; i &amp;lt;= max1; i++ {
    go func(id int, writer io.Writer) {
        defer func() {
            sign &amp;lt;- struct{}{}
        }()
        for j := 1; j &amp;lt;= max2; j++ {
            header := fmt.Sprintf(&quot;\\n[id: %d, iteration: %d]&quot;, id, j)
            data := fmt.Sprintf(&quot; %d&quot;, id*j)
            if protecting &amp;gt; 0 {
                mu.Lock()
            }
            _, err := writer.Write([]byte(header))
            if err != nil {
                log.Printf(&quot;error: %s [%d]&quot;, err, id)
            }
            for k := 0; k &amp;lt; max3; k++ {
                _, err := writer.Write([]byte(data))
                if err != nil {
                    log.Printf(&quot;error: %s [%d]&quot;, err, id)
                }
            }
            if protecting &amp;gt; 0 {
                mu.Unlock()
            }
        }
    }(i, &amp;amp;buffer)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;等待所有goroutine完成&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for i := 0; i &amp;lt; max1; i++ {
    &amp;lt;-sign
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;读取并打印缓冲区内容&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;data, err := ioutil.ReadAll(&amp;amp;buffer)
if err != nil {
    log.Fatalf(&quot;fatal error: %s&quot;, err)
}
log.Printf(&quot;The contents:\\n%s&quot;, data)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;互斥锁的作用&lt;/h2&gt;
&lt;p&gt;在并发编程中，多个goroutine可能会同时访问共享资源，导致数据竞争。互斥锁（&lt;code&gt;sync.Mutex&lt;/code&gt;）用于确保同一时间只有一个goroutine可以访问共享资源，从而避免数据竞争。&lt;/p&gt;
&lt;p&gt;在本示例中，如果&lt;code&gt;protecting&lt;/code&gt;大于0，则会使用互斥锁保护数据写入操作：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if protecting &amp;gt; 0 {
    mu.Lock()
}
_, err := writer.Write([]byte(header))
if err != nil {
    log.Printf(&quot;error: %s [%d]&quot;, err, id)
}
for k := 0; k &amp;lt; max3; k++ {
    _, err := writer.Write([]byte(data))
    if err != nil {
        log.Printf(&quot;error: %s [%d]&quot;, err, id)
    }
}
if protecting &amp;gt; 0 {
    mu.Unlock()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;举一反三&lt;/h2&gt;
&lt;p&gt;通过本示例，我们可以举一反三，理解并应用以下概念：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;并发编程&lt;/strong&gt;：使用goroutine实现并发操作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;互斥锁&lt;/strong&gt;：使用&lt;code&gt;sync.Mutex&lt;/code&gt;保护共享资源，避免数据竞争。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;信号通道&lt;/strong&gt;：使用通道（&lt;code&gt;chan&lt;/code&gt;）实现goroutine间的同步。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;希望通过本教程，您能更好地理解Go语言中的并发编程和互斥锁的使用。祝您编程愉快！&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：使用爱拉托逊斯筛选法获取质数</title><link>https://blog.ithuo.net/posts/go-tutorial-sieve-of-eratosthenes-prime-numbers/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-tutorial-sieve-of-eratosthenes-prime-numbers/</guid><pubDate>Sun, 22 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在本教程中，我们将深入探讨如何使用Go语言编写一个程序来获取小于或等于给定数值的所有质数。我们将使用爱拉托逊斯筛选法（Sieve of Eratosthenes）来实现这一目标，并通过单元测试和基准测试来验证和评估我们的实现。&lt;/p&gt;
&lt;h3&gt;1. 什么是质数？&lt;/h3&gt;
&lt;p&gt;质数是大于1的自然数，且只能被1和它本身整除。例如，2、3、5、7等都是质数。&lt;/p&gt;
&lt;h3&gt;2. 爱拉托逊斯筛选法简介&lt;/h3&gt;
&lt;p&gt;爱拉托逊斯筛选法是一种高效的算法，用于找出一定范围内的所有质数。其基本思想是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;创建一个从2到最大数的列表。&lt;/li&gt;
&lt;li&gt;从列表中选择第一个未标记的数（初始为2），将其所有倍数标记为非质数。&lt;/li&gt;
&lt;li&gt;重复步骤2，直到处理到最大数的平方根为止。&lt;/li&gt;
&lt;li&gt;剩下未标记的数即为质数。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;3. 实现代码&lt;/h3&gt;
&lt;p&gt;我们将分为两个部分：质数生成函数和测试代码。&lt;/p&gt;
&lt;h3&gt;3.1 质数生成函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;package q1

import (
	&quot;math&quot;
)

// GetPrimes 用于获取小于或等于参数max的所有质数。
// 本函数使用的是爱拉托逊斯筛选法（Sieve Of Eratosthenes）。
func GetPrimes(max int) []int {
	if max &amp;lt;= 1 {
		return []int{}
	}
	marks := make([]bool, max)
	var count int
	squareRoot := int(math.Sqrt(float64(max)))
	for i := 2; i &amp;lt;= squareRoot; i++ {
		if marks[i] == false {
			for j := i * i; j &amp;lt; max; j += i {
				if marks[j] == false {
					marks[j] = true
					count++
				}
			}
		}
	}
	primes := make([]int, 0, max-count)
	for i := 2; i &amp;lt; max; i++ {
		if marks[i] == false {
			primes = append(primes, i)
		}
	}
	return primes
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3.2 测试代码&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;package q1

import (
	&quot;testing&quot;
)

var expectedPrimes = []int{
	2, 3, 5, 7, 11, 13, 17, 19,
	23, 29, 31, 37, 41, 43, 47, 53,
	59, 61, 67, 71, 73, 79, 83, 89,
	97, 101, 103, 107, 109, 113, 127, 131,
	137, 139, 149, 151, 157, 163, 167, 173,
	179, 181, 191, 193, 197, 199, 211, 223,
	227, 229, 233, 239, 241, 251, 257, 263,
	269, 271, 277, 281, 283, 293, 307, 311,
	313, 317, 331, 337, 347, 349, 353, 359,
	367, 373, 379, 383, 389, 397, 401, 409,
	419, 421, 431, 433, 439, 443, 449, 457,
	461, 463, 467, 479, 487, 491, 499, 503,
	509, 521, 523, 541, 547, 557, 563, 569,
	571, 577, 587, 593, 599, 601, 607, 613,
	617, 619, 631, 641, 643, 647, 653, 659,
	661, 673, 677, 683, 691, 701, 709, 719,
	727, 733, 739, 743, 751, 757, 761, 769,
	773, 787, 797, 809, 811, 821, 823, 827,
	829, 839, 853, 857, 859, 863, 877, 881,
	883, 887, 907, 911, 919, 929, 937, 941,
	947, 953, 967, 971, 977, 983, 991, 997,
}

func TestGetPrimesWith1000(t *testing.T) {
	max := 1000
	primes := GetPrimes(max)
	for i, prime := range primes {
		expectedPrime := expectedPrimes[i]
		if prime != expectedPrime {
			t.Errorf(&quot;%dth prime number %d is not the expected value %d&quot;,
				i, prime, expectedPrime)
		}
	}
	if t.Failed() == false {
		t.Logf(&quot;The primes less than %d are all correct.&quot;, max)
	}
}

func BenchmarkGetPrimesWith100(b *testing.B) {
	for i := 0; i &amp;lt; b.N; i++ {
		GetPrimes(100)
	}
}

func BenchmarkGetPrimesWith10000(b *testing.B) {
	for i := 0; i &amp;lt; b.N; i++ {
		GetPrimes(10000)
	}
}

func BenchmarkGetPrimesWith1000000(b *testing.B) {
	for i := 0; i &amp;lt; b.N; i++ {
		GetPrimes(1000000)
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. 代码解析&lt;/h3&gt;
&lt;h3&gt;4.1 &lt;code&gt;GetPrimes&lt;/code&gt;函数&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;输入参数&lt;/strong&gt;：&lt;code&gt;max&lt;/code&gt;，表示要找出小于或等于该值的所有质数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;返回值&lt;/strong&gt;：一个包含所有质数的切片。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;步骤解析&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;边界检查&lt;/strong&gt;：如果&lt;code&gt;max&lt;/code&gt;小于等于1，直接返回空切片。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;初始化标记数组&lt;/strong&gt;：创建一个布尔数组&lt;code&gt;marks&lt;/code&gt;，长度为&lt;code&gt;max&lt;/code&gt;，用于标记非质数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;筛选质数&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;计算&lt;code&gt;max&lt;/code&gt;的平方根&lt;code&gt;squareRoot&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;从2开始遍历到&lt;code&gt;squareRoot&lt;/code&gt;，如果当前数未被标记为非质数，则将其所有倍数标记为非质数。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;收集质数&lt;/strong&gt;：遍历&lt;code&gt;marks&lt;/code&gt;数组，将未被标记的数收集到&lt;code&gt;primes&lt;/code&gt;切片中。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;4.2 测试函数&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;TestGetPrimesWith1000&lt;/code&gt;&lt;/strong&gt;：测试&lt;code&gt;GetPrimes&lt;/code&gt;函数是否能正确找出小于1000的所有质数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;基准测试&lt;/strong&gt;：通过&lt;code&gt;Benchmark&lt;/code&gt;函数测试&lt;code&gt;GetPrimes&lt;/code&gt;函数在不同输入规模下的性能。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;5. 运行测试&lt;/h3&gt;
&lt;p&gt;在终端中运行以下命令来执行测试和基准测试：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go test -v
go test -bench=.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;6. 总结&lt;/h3&gt;
&lt;p&gt;通过本教程，我们学习了如何使用Go语言实现爱拉托逊斯筛选法来找出质数，并通过单元测试和基准测试验证和评估我们的实现。希望通过这个例子，您能更好地理解Go语言的基本语法和测试方法。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：单元测试与命令行参数</title><link>https://blog.ithuo.net/posts/go-unit-testing-and-command-line-arguments-tutorial/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-unit-testing-and-command-line-arguments-tutorial/</guid><pubDate>Sat, 21 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;本文将通过一个示例代码，详细介绍Go语言中的单元测试和命令行参数的使用。&lt;/p&gt;
&lt;h2&gt;示例代码解析&lt;/h2&gt;
&lt;h3&gt;代码结构&lt;/h3&gt;
&lt;p&gt;示例代码分为两个部分：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;单元测试部分&lt;/li&gt;
&lt;li&gt;主程序部分&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;单元测试部分&lt;/h3&gt;
&lt;p&gt;单元测试部分位于&lt;code&gt;main_test.go&lt;/code&gt;文件中，包含三个测试函数：&lt;code&gt;TestHello&lt;/code&gt;、&lt;code&gt;TestIntroduce&lt;/code&gt;和&lt;code&gt;TestFail&lt;/code&gt;。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;TestHello&lt;/code&gt;函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func TestHello(t *testing.T) {
	var name string
	greeting, err := hello(name)
	if err == nil {
		t.Errorf(&quot;The error is nil, but it should not be. (name=%q)&quot;, name)
	}
	if greeting != &quot;&quot; {
		t.Errorf(&quot;Nonempty greeting, but it should not be. (name=%q)&quot;, name)
	}
	name = &quot;Robert&quot;
	greeting, err = hello(name)
	if err != nil {
		t.Errorf(&quot;The error is not nil, but it should be. (name=%q)&quot;, name)
	}
	if greeting == &quot;&quot; {
		t.Errorf(&quot;Empty greeting, but it should not be. (name=%q)&quot;, name)
	}
	expected := fmt.Sprintf(&quot;Hello, %s!&quot;, name)
	if greeting != expected {
		t.Errorf(&quot;The actual greeting %q is not the expected. (name=%q)&quot;, greeting, name)
	}
	t.Logf(&quot;The expected greeting is %q.\\n&quot;, expected)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;解析：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;测试&lt;code&gt;hello&lt;/code&gt;函数的行为。&lt;/li&gt;
&lt;li&gt;当&lt;code&gt;name&lt;/code&gt;为空时，期望返回错误和空字符串。&lt;/li&gt;
&lt;li&gt;当&lt;code&gt;name&lt;/code&gt;为&quot;Robert&quot;时，期望返回正确的问候语。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;code&gt;TestIntroduce&lt;/code&gt;函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func TestIntroduce(t *testing.T) {
	intro := introduce()
	expected := &quot;Welcome to my Golang column.&quot;
	if intro != expected {
		t.Errorf(&quot;The actual introduce %q is not the expected.&quot;, intro)
	}
	t.Logf(&quot;The expected introduce is %q.\\n&quot;, expected)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;解析：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;测试&lt;code&gt;introduce&lt;/code&gt;函数的行为。&lt;/li&gt;
&lt;li&gt;期望返回固定的介绍语。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;code&gt;TestFail&lt;/code&gt;函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func TestFail(t *testing.T) {
	//t.Fail()
	t.FailNow() // 此调用会让当前的测试立即失败。
	t.Log(&quot;Failed.&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;解析：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;演示如何使测试失败。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;t.FailNow()&lt;/code&gt;会立即终止测试。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;主程序部分&lt;/h3&gt;
&lt;p&gt;主程序部分位于&lt;code&gt;main.go&lt;/code&gt;文件中，包含&lt;code&gt;init&lt;/code&gt;、&lt;code&gt;main&lt;/code&gt;、&lt;code&gt;hello&lt;/code&gt;和&lt;code&gt;introduce&lt;/code&gt;函数。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;init&lt;/code&gt;函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func init() {
	flag.StringVar(&amp;amp;name, &quot;name&quot;, &quot;everyone&quot;, &quot;The greeting object.&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;解析：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用&lt;code&gt;flag&lt;/code&gt;包定义命令行参数&lt;code&gt;name&lt;/code&gt;，默认值为&quot;everyone&quot;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;code&gt;main&lt;/code&gt;函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func main() {
	flag.Parse()
	greeting, err := hello(name)
	if err != nil {
		fmt.Printf(&quot;error: %s\\n&quot;, err)
		return
	}
	fmt.Println(greeting, introduce())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;解析：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;解析命令行参数。&lt;/li&gt;
&lt;li&gt;调用&lt;code&gt;hello&lt;/code&gt;函数生成问候语。&lt;/li&gt;
&lt;li&gt;调用&lt;code&gt;introduce&lt;/code&gt;函数生成介绍语。&lt;/li&gt;
&lt;li&gt;输出结果。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;code&gt;hello&lt;/code&gt;函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func hello(name string) (string, error) {
	if name == &quot;&quot; {
		return &quot;&quot;, errors.New(&quot;empty name&quot;)
	}
	return fmt.Sprintf(&quot;Hello, %s!&quot;, name), nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;解析：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;根据传入的&lt;code&gt;name&lt;/code&gt;生成问候语。&lt;/li&gt;
&lt;li&gt;如果&lt;code&gt;name&lt;/code&gt;为空，返回错误。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;code&gt;introduce&lt;/code&gt;函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func introduce() string {
	return &quot;Welcome to my Golang column.&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;解析：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;返回固定的介绍语。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;最佳实践&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;单元测试&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;使用&lt;code&gt;testing&lt;/code&gt;包编写单元测试。&lt;/li&gt;
&lt;li&gt;测试函数命名以&lt;code&gt;Test&lt;/code&gt;开头。&lt;/li&gt;
&lt;li&gt;使用&lt;code&gt;t.Errorf&lt;/code&gt;报告错误，使用&lt;code&gt;t.Logf&lt;/code&gt;记录日志。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;命令行参数&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;使用&lt;code&gt;flag&lt;/code&gt;包解析命令行参数。&lt;/li&gt;
&lt;li&gt;在&lt;code&gt;init&lt;/code&gt;函数中定义命令行参数。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;错误处理&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;函数返回错误时，优先处理错误。&lt;/li&gt;
&lt;li&gt;使用&lt;code&gt;errors.New&lt;/code&gt;创建错误信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;举一反三&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;扩展问候语功能&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;可以增加更多的问候语选项，例如根据时间段问候（早上好、下午好、晚上好）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;增加更多命令行参数&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;可以增加更多的命令行参数，例如&lt;code&gt;age&lt;/code&gt;、&lt;code&gt;location&lt;/code&gt;，并在问候语中使用这些参数。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;改进错误处理&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;可以使用自定义错误类型，提供更详细的错误信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;通过以上示例和解析，相信你已经掌握了Go语言中单元测试和命令行参数的基本用法。希望你能在实际项目中灵活运用这些知识，编写出高质量的Go代码。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：为函数编写测试代码</title><link>https://blog.ithuo.net/posts/go-language-tutorial-understanding-testcode-step-by-step/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-language-tutorial-understanding-testcode-step-by-step/</guid><pubDate>Fri, 20 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在本教程中，我们将通过一个简单的Go语言程序来学习Go语言的基本概念和一些高级特性。我们将逐步解析代码，解释其原理，并举一反三地探讨相关知识点。&lt;/p&gt;
&lt;h2&gt;代码概览&lt;/h2&gt;
&lt;p&gt;我们将从以下代码开始：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;errors&quot;
	&quot;flag&quot;
	&quot;fmt&quot;
)

var name string

func init() {
	flag.StringVar(&amp;amp;name, &quot;name&quot;, &quot;everyone&quot;, &quot;The greeting object.&quot;)
}

func main() {
	flag.Parse()
	greeting, err := hello(name)
	if err != nil {
		fmt.Printf(&quot;error: %s\\n&quot;, err)
		return
	}
	fmt.Println(greeting, introduce())
}

// hello 用于生成问候内容。
func hello(name string) (string, error) {
	if name == &quot;&quot; {
		return &quot;&quot;, errors.New(&quot;empty name&quot;)
	}
	return fmt.Sprintf(&quot;Hello, %s!&quot;, name), nil
}

// introduce 用于生成介绍内容。
func introduce() string {
	return &quot;Welcome to my Golang column.&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;代码解析&lt;/h2&gt;
&lt;h3&gt;包和导入&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;errors&quot;
	&quot;flag&quot;
	&quot;fmt&quot;
)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;package main&lt;/code&gt;：声明程序的包名为&lt;code&gt;main&lt;/code&gt;，表示这是一个可执行程序。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;import&lt;/code&gt;：导入标准库中的&lt;code&gt;errors&lt;/code&gt;、&lt;code&gt;flag&lt;/code&gt;和&lt;code&gt;fmt&lt;/code&gt;包，分别用于错误处理、命令行参数解析和格式化输出。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;全局变量&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;var name string
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;声明一个全局变量&lt;code&gt;name&lt;/code&gt;，用于存储命令行参数的值。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;初始化函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func init() {
	flag.StringVar(&amp;amp;name, &quot;name&quot;, &quot;everyone&quot;, &quot;The greeting object.&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;init&lt;/code&gt;函数在&lt;code&gt;main&lt;/code&gt;函数之前自动执行，用于初始化全局变量。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;flag.StringVar&lt;/code&gt;：将命令行参数&lt;code&gt;name&lt;/code&gt;的值绑定到&lt;code&gt;name&lt;/code&gt;变量，默认值为&lt;code&gt;&quot;everyone&quot;&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;主函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func main() {
	flag.Parse()
	greeting, err := hello(name)
	if err != nil {
		fmt.Printf(&quot;error: %s\\n&quot;, err)
		return
	}
	fmt.Println(greeting, introduce())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;flag.Parse&lt;/code&gt;：解析命令行参数。&lt;/li&gt;
&lt;li&gt;调用&lt;code&gt;hello&lt;/code&gt;函数生成问候语，并处理可能的错误。&lt;/li&gt;
&lt;li&gt;如果没有错误，打印问候语和介绍内容。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;code&gt;hello&lt;/code&gt;函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func hello(name string) (string, error) {
	if name == &quot;&quot; {
		return &quot;&quot;, errors.New(&quot;empty name&quot;)
	}
	return fmt.Sprintf(&quot;Hello, %s!&quot;, name), nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;接受一个字符串参数&lt;code&gt;name&lt;/code&gt;，返回问候语和可能的错误。&lt;/li&gt;
&lt;li&gt;如果&lt;code&gt;name&lt;/code&gt;为空，返回错误&lt;code&gt;&quot;empty name&quot;&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;否则，返回格式化的问候语。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;code&gt;introduce&lt;/code&gt;函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func introduce() string {
	return &quot;Welcome to my Golang column.&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;返回固定的介绍内容。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;测试代码&lt;/h2&gt;
&lt;p&gt;为了确保我们的代码正确无误，我们编写了以下测试代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;fmt&quot;
	&quot;testing&quot;
)

func TestHello(t *testing.T) {
	var name string
	greeting, err := hello(name)
	if err == nil {
		t.Errorf(&quot;The error is nil, but it should not be. (name=%q)&quot;, name)
	}
	if greeting != &quot;&quot; {
		t.Errorf(&quot;Nonempty greeting, but it should not be. (name=%q)&quot;, name)
	}
	name = &quot;Robert&quot;
	greeting, err = hello(name)
	if err != nil {
		t.Errorf(&quot;The error is not nil, but it should be. (name=%q)&quot;, name)
	}
	if greeting == &quot;&quot; {
		t.Errorf(&quot;Empty greeting, but it should not be. (name=%q)&quot;, name)
	}
	expected := fmt.Sprintf(&quot;Hello, %s!&quot;, name)
	if greeting != expected {
		t.Errorf(&quot;The actual greeting %q is not the expected. (name=%q)&quot;, greeting, name)
	}
	t.Logf(&quot;The expected greeting is %q.\\n&quot;, expected)
}

func testIntroduce(t *testing.T) { // 请注意这个测试函数的名称。
	intro := introduce()
	expected := &quot;Welcome to my Golang column.&quot;
	if intro != expected {
		t.Errorf(&quot;The actual introduce %q is not the expected.&quot;, intro)
	}
	t.Logf(&quot;The expected introduce is %q.\\n&quot;, expected)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;测试解析&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;TestHello&lt;/code&gt;：测试&lt;code&gt;hello&lt;/code&gt;函数的各种情况，包括空字符串和正常字符串。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;testIntroduce&lt;/code&gt;：测试&lt;code&gt;introduce&lt;/code&gt;函数的返回值。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;通过这个简单的Go语言程序，我们学习了以下内容：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;包和导入&lt;/strong&gt;：如何声明包和导入标准库。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;全局变量&lt;/strong&gt;：如何声明和使用全局变量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;初始化函数&lt;/strong&gt;：&lt;code&gt;init&lt;/code&gt;函数的作用和使用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;主函数&lt;/strong&gt;：&lt;code&gt;main&lt;/code&gt;函数的结构和基本逻辑。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;函数&lt;/strong&gt;：如何定义和调用函数，处理错误。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;测试&lt;/strong&gt;：如何编写和运行测试代码。&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：深入理解defer、panic和recover</title><link>https://blog.ithuo.net/posts/go-language-defer-panic-recover/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-language-defer-panic-recover/</guid><pubDate>Thu, 19 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在Go语言中，&lt;code&gt;defer&lt;/code&gt;、&lt;code&gt;panic&lt;/code&gt;和&lt;code&gt;recover&lt;/code&gt;是三个非常重要的关键字，它们在处理错误和资源管理方面起着至关重要的作用。本文将通过几个示例代码，深入浅出地讲解这三个关键字的用法和注意事项。&lt;/p&gt;
&lt;h2&gt;示例1：defer的基本用法&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;package main

import &quot;fmt&quot;

func main() {
	defer fmt.Println(&quot;first defer&quot;)
	for i := 0; i &amp;lt; 3; i++ {
		defer fmt.Printf(&quot;defer in for [%d]\\n&quot;, i)
	}
	defer fmt.Println(&quot;last defer&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;解析&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;defer的执行顺序&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;defer&lt;/code&gt;语句会将其后的函数调用推迟到包含它的函数即将返回的时候执行。&lt;/li&gt;
&lt;li&gt;多个&lt;code&gt;defer&lt;/code&gt;语句的执行顺序是&lt;strong&gt;后进先出&lt;/strong&gt;（LIFO）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;代码执行顺序&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;main&lt;/code&gt;函数开始执行，首先注册&lt;code&gt;defer fmt.Println(&quot;first defer&quot;)&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;进入&lt;code&gt;for&lt;/code&gt;循环，依次注册&lt;code&gt;defer fmt.Printf(&quot;defer in for [%d]\\n&quot;, i)&lt;/code&gt;，其中&lt;code&gt;i&lt;/code&gt;的值分别为0、1、2。&lt;/li&gt;
&lt;li&gt;注册&lt;code&gt;defer fmt.Println(&quot;last defer&quot;)&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;main&lt;/code&gt;函数即将返回时，按照后进先出的顺序执行所有的&lt;code&gt;defer&lt;/code&gt;语句。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;输出结果&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;last defer
defer in for [2]
defer in for [1]
defer in for [0]
first defer
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;示例2：panic和recover的用法&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;errors&quot;
	&quot;fmt&quot;
)

func main() {
	fmt.Println(&quot;Enter function main.&quot;)

	defer func() {
		fmt.Println(&quot;Enter defer function.&quot;)

		// recover函数的正确用法。
		if p := recover(); p != nil {
			fmt.Printf(&quot;panic: %s\\n&quot;, p)
		}

		fmt.Println(&quot;Exit defer function.&quot;)
	}()

	// recover函数的错误用法。
	fmt.Printf(&quot;no panic: %v\\n&quot;, recover())

	// 引发panic。
	panic(errors.New(&quot;something wrong&quot;))

	// recover函数的错误用法。
	p := recover()
	fmt.Printf(&quot;panic: %s\\n&quot;, p)

	fmt.Println(&quot;Exit function main.&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;解析&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;panic&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;panic&lt;/code&gt;用于引发一个恐慌，终止当前函数的执行，并开始沿着调用栈向上回溯，直到遇到&lt;code&gt;recover&lt;/code&gt;或程序崩溃。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;recover&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;recover&lt;/code&gt;用于终止&lt;code&gt;panic&lt;/code&gt;的回溯，恢复正常的执行流程。它只能在&lt;code&gt;defer&lt;/code&gt;函数中有效。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;代码执行顺序&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;main&lt;/code&gt;函数开始执行，打印&lt;code&gt;&quot;Enter function main.&quot;&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;注册&lt;code&gt;defer&lt;/code&gt;函数。&lt;/li&gt;
&lt;li&gt;调用&lt;code&gt;recover()&lt;/code&gt;，此时没有&lt;code&gt;panic&lt;/code&gt;，返回&lt;code&gt;nil&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;引发&lt;code&gt;panic&lt;/code&gt;，错误信息为&lt;code&gt;&quot;something wrong&quot;&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;defer&lt;/code&gt;函数被调用，&lt;code&gt;recover&lt;/code&gt;捕获到&lt;code&gt;panic&lt;/code&gt;，打印错误信息。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;defer&lt;/code&gt;函数执行完毕，&lt;code&gt;main&lt;/code&gt;函数继续执行。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;输出结果&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Enter function main.
no panic: &amp;lt;nil&amp;gt;
Enter defer function.
panic: something wrong
Exit defer function.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;示例3：panic的正确和错误用法&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;errors&quot;
	&quot;fmt&quot;
)

func main() {
	fmt.Println(&quot;Enter function main.&quot;)
	caller()
	fmt.Println(&quot;Exit function main.&quot;)
}

func caller() {
	fmt.Println(&quot;Enter function caller.&quot;)
	panic(errors.New(&quot;something wrong&quot;)) // 正例。
	panic(fmt.Println)                   // 反例。
	fmt.Println(&quot;Exit function caller.&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;解析&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;panic的正确用法&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;panic(errors.New(&quot;something wrong&quot;))&lt;/code&gt;：引发一个带有错误信息的&lt;code&gt;panic&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;panic的错误用法&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;panic(fmt.Println)&lt;/code&gt;：&lt;code&gt;fmt.Println&lt;/code&gt;是一个函数，不是错误信息或字符串，使用不当。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;代码执行顺序&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;main&lt;/code&gt;函数开始执行，打印&lt;code&gt;&quot;Enter function main.&quot;&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;调用&lt;code&gt;caller&lt;/code&gt;函数。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;caller&lt;/code&gt;函数引发&lt;code&gt;panic&lt;/code&gt;，错误信息为&lt;code&gt;&quot;something wrong&quot;&lt;/code&gt;，程序终止。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;输出结果&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Enter function main.
Enter function caller.
panic: something wrong
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;通过以上示例，我们可以总结出以下几点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;defer&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;用于延迟函数的执行，直到包含它的函数即将返回时执行。&lt;/li&gt;
&lt;li&gt;多个&lt;code&gt;defer&lt;/code&gt;语句按照后进先出的顺序执行。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;panic&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;用于引发一个恐慌，终止当前函数的执行，并开始沿着调用栈向上回溯。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;recover&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;用于终止&lt;code&gt;panic&lt;/code&gt;的回溯，恢复正常的执行流程。只能在&lt;code&gt;defer&lt;/code&gt;函数中有效。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;通过理解和掌握&lt;code&gt;defer&lt;/code&gt;、&lt;code&gt;panic&lt;/code&gt;和&lt;code&gt;recover&lt;/code&gt;的用法，可以更好地处理Go语言中的错误和资源管理，提高代码的健壮性和可维护性。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：错误处理</title><link>https://blog.ithuo.net/posts/go-error-handling-tutorial/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-error-handling-tutorial/</guid><pubDate>Wed, 18 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在Go语言中，错误处理是一个非常重要的部分。通过合理的错误处理，可以提高程序的健壮性和可维护性。本文将通过几个示例代码，详细讲解Go语言中的错误处理机制，并举一反三，帮助你更好地理解和应用。&lt;/p&gt;
&lt;h3&gt;示例1：基本错误处理&lt;/h3&gt;
&lt;p&gt;首先，我们来看一个简单的错误处理示例。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;errors&quot;
	&quot;fmt&quot;
)

func echo(request string) (response string, err error) {
	if request == &quot;&quot; {
		err = errors.New(&quot;empty request&quot;)
		return
	}
	response = fmt.Sprintf(&quot;echo: %s&quot;, request)
	return
}

func main() {
	for _, req := range []string{&quot;&quot;, &quot;hello!&quot;} {
		fmt.Printf(&quot;request: %s\\n&quot;, req)
		resp, err := echo(req)
		if err != nil {
			fmt.Printf(&quot;error: %s\\n&quot;, err)
			continue
		}
		fmt.Printf(&quot;response: %s\\n&quot;, resp)
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;解释&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;定义错误&lt;/strong&gt;：使用&lt;code&gt;errors.New&lt;/code&gt;函数创建一个新的错误。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;返回错误&lt;/strong&gt;：在函数&lt;code&gt;echo&lt;/code&gt;中，如果请求为空，则返回一个错误。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;处理错误&lt;/strong&gt;：在&lt;code&gt;main&lt;/code&gt;函数中，调用&lt;code&gt;echo&lt;/code&gt;函数并检查返回的错误。如果有错误，则打印错误信息并继续处理下一个请求。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;举一反三&lt;/h3&gt;
&lt;p&gt;你可以将这种错误处理模式应用到其他函数中。例如，检查文件是否存在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func checkFileExists(filename string) error {
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		return errors.New(&quot;file does not exist&quot;)
	}
	return nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;示例2：深入错误类型&lt;/h3&gt;
&lt;p&gt;在Go语言中，错误不仅仅是简单的字符串。你可以定义自己的错误类型，并通过类型断言来处理不同类型的错误。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;fmt&quot;
	&quot;os&quot;
	&quot;os/exec&quot;
)

// underlyingError 返回已知的操作系统相关错误的潜在错误值。
func underlyingError(err error) error {
	switch err := err.(type) {
	case *os.PathError:
		return err.Err
	case *os.LinkError:
		return err.Err
	case *os.SyscallError:
		return err.Err
	case *exec.Error:
		return err.Err
	}
	return err
}

func main() {
	r, w, err := os.Pipe()
	if err != nil {
		fmt.Printf(&quot;unexpected error: %s\\n&quot;, err)
		return
	}
	r.Close()
	_, err = w.Write([]byte(&quot;hi&quot;))
	uError := underlyingError(err)
	fmt.Printf(&quot;underlying error: %s (type: %T)\\n&quot;, uError, uError)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;解释&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;类型断言&lt;/strong&gt;：通过类型断言，检查错误的具体类型，并返回潜在的错误值。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;处理特定错误&lt;/strong&gt;：在&lt;code&gt;main&lt;/code&gt;函数中，制造一个&lt;code&gt;os.PathError&lt;/code&gt;类型的错误，并通过&lt;code&gt;underlyingError&lt;/code&gt;函数获取潜在的错误值。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;举一反三&lt;/h3&gt;
&lt;p&gt;你可以定义自己的错误类型，并通过类型断言来处理。例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type MyError struct {
	Code int
	Msg  string
}

func (e *MyError) Error() string {
	return fmt.Sprintf(&quot;code: %d, msg: %s&quot;, e.Code, e.Msg)
}

func checkValue(val int) error {
	if val &amp;lt; 0 {
		return &amp;amp;MyError{Code: 400, Msg: &quot;negative value&quot;}
	}
	return nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;示例3：自定义错误类型&lt;/h3&gt;
&lt;p&gt;在Go语言中，你可以定义自己的错误类型，以便更好地描述和处理错误。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;fmt&quot;
	&quot;os&quot;
	&quot;os/exec&quot;
	&quot;strconv&quot;
)

type Errno int

func (e Errno) Error() string {
	return &quot;errno &quot; + strconv.Itoa(int(e))
}

func main() {
	const (
		ERR0 = Errno(0)
		ERR1 = Errno(1)
		ERR2 = Errno(2)
	)
	var myErr error = Errno(0)
	switch myErr {
	case ERR0:
		fmt.Println(&quot;ERR0&quot;)
	case ERR1:
		fmt.Println(&quot;ERR1&quot;)
	case ERR2:
		fmt.Println(&quot;ERR2&quot;)
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;解释&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;定义错误类型&lt;/strong&gt;：定义一个&lt;code&gt;Errno&lt;/code&gt;类型，并实现&lt;code&gt;Error&lt;/code&gt;方法。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用错误类型&lt;/strong&gt;：在&lt;code&gt;main&lt;/code&gt;函数中，通过类型断言和switch语句处理不同的错误类型。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;举一反三&lt;/h3&gt;
&lt;p&gt;你可以定义更多的错误类型，并在程序中使用。例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type ValidationError struct {
	Field string
	Msg   string
}

func (e *ValidationError) Error() string {
	return fmt.Sprintf(&quot;validation error: field=%s, msg=%s&quot;, e.Field, e.Msg)
}

func validateInput(input string) error {
	if input == &quot;&quot; {
		return &amp;amp;ValidationError{Field: &quot;input&quot;, Msg: &quot;cannot be empty&quot;}
	}
	return nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;通过以上示例，我们学习了Go语言中基本的错误处理、深入的错误类型处理以及自定义错误类型。希望这些内容能帮助你更好地理解和应用Go语言的错误处理机制。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：switch的用法</title><link>https://blog.ithuo.net/posts/go-language-uses-switch/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-language-uses-switch/</guid><pubDate>Tue, 17 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;这是一篇关于Go语言中switch语句的教程。通过对示例代码的分析,我们可以深入理解switch语句的用法和注意事项。&lt;/p&gt;
&lt;h2&gt;switch语句基本语法&lt;/h2&gt;
&lt;p&gt;switch语句的基本语法如下:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;switch 表达式 {
case 表达式1:
    // 代码块1
case 表达式2:
    // 代码块2
default:
    // 默认代码块
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;switch语句会根据表达式的值,与case后的表达式进行匹配。如果匹配成功,就执行对应的代码块;如果都不匹配,就执行default代码块。&lt;/p&gt;
&lt;h2&gt;case表达式的限制&lt;/h2&gt;
&lt;p&gt;在示例1中,我们看到下面的代码无法编译通过:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;value3 := [...]int8{0, 1, 2, 3, 4, 5, 6}
switch value3[4] {
case 0, 1, 2:
    fmt.Println(&quot;0 or 1 or 2&quot;)
case 2, 3, 4:
    fmt.Println(&quot;2 or 3 or 4&quot;)
case 4, 5, 6:
    fmt.Println(&quot;4 or 5 or 6&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是因为case后的表达式中,不能有重复的值。在上面的代码中,2和4都出现了两次,所以编译器会报错。&lt;/p&gt;
&lt;h2&gt;case表达式的类型&lt;/h2&gt;
&lt;p&gt;在示例2中,我们看到case后的表达式可以是一个值,也可以是一个变量:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;value5 := [...]int8{0, 1, 2, 3, 4, 5, 6}
switch value5[4] {
case value5[0], value5[1], value5[2]:
    fmt.Println(&quot;0 or 1 or 2&quot;)
case value5[2], value5[3], value5[4]:
    fmt.Println(&quot;2 or 3 or 4&quot;)
case value5[4], value5[5], value5[6]:
    fmt.Println(&quot;4 or 5 or 6&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;case后的表达式类型必须与switch表达式的类型一致。在这个例子中,value5是int8类型,所以case后的表达式也必须是int8类型。&lt;/p&gt;
&lt;h2&gt;Type Switch&lt;/h2&gt;
&lt;p&gt;除了对值进行判断,switch还可以对变量的类型进行判断,这就是Type Switch。示例3展示了一个Type Switch的例子:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;value6 := interface{}(byte(127))
switch t := value6.(type) {
case uint8, uint16:
    fmt.Println(&quot;uint8 or uint16&quot;)
case byte:
    fmt.Printf(&quot;byte&quot;)
default:
    fmt.Printf(&quot;unsupported type: %T&quot;, t)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个例子中,value6是一个空接口类型的变量,它的实际类型是byte。通过t := value6.(type)语句,可以获取到value6的实际类型,并赋值给变量t。&lt;/p&gt;
&lt;p&gt;然后,switch会根据t的类型,与case后声明的类型进行匹配。需要注意的是,case后只能是类型,不能是表达式。&lt;/p&gt;
&lt;h2&gt;switch表达式的限制&lt;/h2&gt;
&lt;p&gt;最后,我们再来看一个无法编译通过的例子:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;value1 := [...]int8{0, 1, 2, 3, 4, 5, 6}
switch 1 + 3 {
case value1[0], value1[1]:
    fmt.Println(&quot;0 or 1&quot;)
case value1[2], value1[3]:
    fmt.Println(&quot;2 or 3&quot;)
case value1[4], value1[5], value1[6]:
    fmt.Println(&quot;4 or 5 or 6&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;switch后的表达式必须是一个单一的值,不能是表达式。1 + 3是一个表达式,所以编译器会报错。&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;通过以上示例,我们可以总结出switch语句的几个关键点:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;case后的表达式不能有重复值。&lt;/li&gt;
&lt;li&gt;case后的表达式类型必须与switch表达式的类型一致。&lt;/li&gt;
&lt;li&gt;可以使用Type Switch对变量的类型进行判断。&lt;/li&gt;
&lt;li&gt;switch后的表达式必须是一个单一的值,不能是表达式。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;希望通过这篇教程,你能够更好地理解和运用Go语言的switch语句。在实际开发中,灵活运用switch语句可以让代码更加简洁和易读。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：深入理解切片和数组的操作</title><link>https://blog.ithuo.net/posts/go-slice-array-tutorial/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-slice-array-tutorial/</guid><pubDate>Mon, 16 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在本教程中，我们将通过一个示例代码来深入理解Go语言中切片和数组的操作。我们将逐步分析代码，解释其工作原理，并举一反三，帮助你更好地掌握这些概念。&lt;/p&gt;
&lt;h3&gt;示例代码&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;package main

import &quot;fmt&quot;

func main() {
	// 示例1。
	numbers1 := []int{1, 2, 3, 4, 5, 6}
	for i := range numbers1 {
		if i == 3 {
			numbers1[i] |= i
		}
	}
	fmt.Println(numbers1)
	fmt.Println()

	// 示例2。
	numbers2 := [...]int{1, 2, 3, 4, 5, 6}
	maxIndex2 := len(numbers2) - 1
	for i, e := range numbers2 {
		if i == maxIndex2 {
			numbers2[0] += e
		} else {
			numbers2[i+1] += e
		}
	}
	fmt.Println(numbers2)
	fmt.Println()

	// 示例3。
	numbers3 := []int{1, 2, 3, 4, 5, 6}
	maxIndex3 := len(numbers2) - 1
	for i, e := range numbers3 {
		if i == maxIndex3 {
			numbers3[0] += e
		} else {
			numbers3[i+1] += e
		}
	}
	fmt.Println(numbers3)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;示例1：切片的按位或操作&lt;/h3&gt;
&lt;p&gt;在第一个示例中，我们定义了一个切片 &lt;code&gt;numbers1&lt;/code&gt;，并对其进行遍历。当索引 &lt;code&gt;i&lt;/code&gt; 等于 3 时，对 &lt;code&gt;numbers1[i]&lt;/code&gt; 进行按位或操作。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;numbers1 := []int{1, 2, 3, 4, 5, 6}
for i := range numbers1 {
	if i == 3 {
		numbers1[i] |= i
	}
}
fmt.Println(numbers1)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;解释&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;numbers1[i] |= i&lt;/code&gt; 是按位或操作。对于 &lt;code&gt;i == 3&lt;/code&gt;，&lt;code&gt;numbers1&lt;/code&gt; 的值为 4，&lt;code&gt;4 | 3&lt;/code&gt; 的结果是 7。&lt;/li&gt;
&lt;li&gt;因此，&lt;code&gt;numbers1&lt;/code&gt; 的结果为 ``。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;示例2：数组的元素累加&lt;/h3&gt;
&lt;p&gt;在第二个示例中，我们定义了一个数组 &lt;code&gt;numbers2&lt;/code&gt;，并对其进行遍历。根据索引位置不同，对数组元素进行累加操作。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;numbers2 := [...]int{1, 2, 3, 4, 5, 6}
maxIndex2 := len(numbers2) - 1
for i, e := range numbers2 {
	if i == maxIndex2 {
		numbers2[0] += e
	} else {
		numbers2[i+1] += e
	}
}
fmt.Println(numbers2)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;解释&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;maxIndex2&lt;/code&gt; 是数组的最后一个索引。&lt;/li&gt;
&lt;li&gt;如果当前索引 &lt;code&gt;i&lt;/code&gt; 是最后一个索引，则将最后一个元素的值加到第一个元素上。&lt;/li&gt;
&lt;li&gt;否则，将当前元素的值加到下一个元素上。&lt;/li&gt;
&lt;li&gt;最终结果为 ``。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;示例3：切片的元素累加&lt;/h3&gt;
&lt;p&gt;在第三个示例中，我们定义了一个切片 &lt;code&gt;numbers3&lt;/code&gt;，并对其进行类似于示例2的操作。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;numbers3 := []int{1, 2, 3, 4, 5, 6}
maxIndex3 := len(numbers2) - 1
for i, e := range numbers3 {
	if i == maxIndex3 {
		numbers3[0] += e
	} else {
		numbers3[i+1] += e
	}
}
fmt.Println(numbers3)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;解释&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;maxIndex3&lt;/code&gt; 是数组 &lt;code&gt;numbers2&lt;/code&gt; 的最后一个索引（注意这里的 &lt;code&gt;maxIndex3&lt;/code&gt; 应该是 &lt;code&gt;len(numbers3) - 1&lt;/code&gt;，这是一个小错误）。&lt;/li&gt;
&lt;li&gt;操作逻辑与示例2相同，但由于 &lt;code&gt;maxIndex3&lt;/code&gt; 的错误，实际操作会有偏差。&lt;/li&gt;
&lt;li&gt;正确的结果应该是 ``，但由于错误，结果会有所不同。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;通过这三个示例，我们可以看到：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;切片和数组的定义和操作方式。&lt;/li&gt;
&lt;li&gt;按位或操作的使用。&lt;/li&gt;
&lt;li&gt;如何根据索引位置对元素进行累加操作。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这些示例展示了Go语言中切片和数组的基本操作和一些常见的用法。理解这些概念后，你可以更灵活地处理数据结构，编写高效的Go代码。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：并发编程</title><link>https://blog.ithuo.net/posts/go-concurrency-tutorial-1/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-concurrency-tutorial-1/</guid><pubDate>Sun, 15 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在本教程中，我们将通过两个示例代码来讲解Go语言中的并发编程。我们将深入浅出地讲解原理，帮助你更好地理解和应用Go语言的并发特性。&lt;/p&gt;
&lt;h3&gt;示例1：使用通道（Channel）进行并发控制&lt;/h3&gt;
&lt;h3&gt;代码解析&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;fmt&quot;
	//&quot;time&quot;
)

func main() {
	num := 10
	sign := make(chan struct{}, num)

	for i := 0; i &amp;lt; num; i++ {
		go func() {
			fmt.Println(i)
			sign &amp;lt;- struct{}{}
		}()
	}

	// 办法1。
	//time.Sleep(time.Millisecond * 500)

	// 办法2。
	for j := 0; j &amp;lt; num; j++ {
		&amp;lt;-sign
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;代码讲解&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;通道的创建&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sign := make(chan struct{}, num)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里我们创建了一个缓冲通道&lt;code&gt;sign&lt;/code&gt;，缓冲大小为&lt;code&gt;num&lt;/code&gt;（10）。通道用于在goroutine之间传递信号。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;启动多个goroutine&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for i := 0; i &amp;lt; num; i++ {
    go func() {
        fmt.Println(i)
        sign &amp;lt;- struct{}{}
    }()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们启动了&lt;code&gt;num&lt;/code&gt;个goroutine，每个goroutine都会打印变量&lt;code&gt;i&lt;/code&gt;的值，并向通道&lt;code&gt;sign&lt;/code&gt;发送一个空结构体&lt;code&gt;struct{}&lt;/code&gt;作为信号。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;等待所有goroutine完成&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for j := 0; j &amp;lt; num; j++ {
    &amp;lt;-sign
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过从通道&lt;code&gt;sign&lt;/code&gt;接收信号，我们确保所有goroutine都已经完成。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;举一反三&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;通道的缓冲区&lt;/strong&gt;：可以根据需要调整通道的缓冲区大小，以控制并发的数量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;通道的类型&lt;/strong&gt;：可以使用不同类型的通道来传递不同类型的数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;示例2：使用原子操作进行并发控制&lt;/h3&gt;
&lt;h3&gt;代码解析&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;fmt&quot;
	&quot;sync/atomic&quot;
	&quot;time&quot;
)

func main() {
	var count uint32
	trigger := func(i uint32, fn func()) {
		for {
			if n := atomic.LoadUint32(&amp;amp;count); n == i {
				fn()
				atomic.AddUint32(&amp;amp;count, 1)
				break
			}
			time.Sleep(time.Nanosecond)
		}
	}
	for i := uint32(0); i &amp;lt; 10; i++ {
		go func(i uint32) {
			fn := func() {
				fmt.Println(i)
			}
			trigger(i, fn)
		}(i)
	}
	trigger(10, func() {})
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;代码讲解&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;原子变量的使用&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var count uint32
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们使用一个无符号32位整数&lt;code&gt;count&lt;/code&gt;作为计数器，通过原子操作来保证并发安全。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;触发函数&lt;/strong&gt;**&lt;code&gt;trigger&lt;/code&gt;**：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;trigger := func(i uint32, fn func()) {
    for {
        if n := atomic.LoadUint32(&amp;amp;count); n == i {
            fn()
            atomic.AddUint32(&amp;amp;count, 1)
            break
        }
        time.Sleep(time.Nanosecond)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;触发函数&lt;code&gt;trigger&lt;/code&gt;会不断检查&lt;code&gt;count&lt;/code&gt;的值是否等于&lt;code&gt;i&lt;/code&gt;，如果相等则执行传入的函数&lt;code&gt;fn&lt;/code&gt;，并将&lt;code&gt;count&lt;/code&gt;加1。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;启动多个goroutine&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for i := uint32(0); i &amp;lt; 10; i++ {
    go func(i uint32) {
        fn := func() {
            fmt.Println(i)
        }
        trigger(i, fn)
    }(i)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们启动了10个goroutine，每个goroutine都会调用&lt;code&gt;trigger&lt;/code&gt;函数，确保按顺序打印&lt;code&gt;i&lt;/code&gt;的值。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;等待所有goroutine完成&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;trigger(10, func() {})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后，我们调用&lt;code&gt;trigger(10, func() {})&lt;/code&gt;来等待所有goroutine完成。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;拓展&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;原子操作&lt;/strong&gt;：可以使用&lt;code&gt;sync/atomic&lt;/code&gt;包中的其他原子操作函数，如&lt;code&gt;atomic.StoreUint32&lt;/code&gt;、&lt;code&gt;atomic.CompareAndSwapUint32&lt;/code&gt;等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;触发条件&lt;/strong&gt;：可以根据需要修改触发条件，以实现不同的并发控制逻辑。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;通过这两个示例，我们学习了如何使用通道和原子操作来进行并发控制。通道适用于需要在goroutine之间传递信号或数据的场景，而原子操作则适用于需要高效、低延迟的并发控制场景。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：深入理解不可寻址值</title><link>https://blog.ithuo.net/posts/go-language-tutorial-understanding-unaddressable-values/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-language-tutorial-understanding-unaddressable-values/</guid><pubDate>Sat, 14 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在Go语言中，理解值的可寻址性是编写高效代码的关键之一。本文将通过一个示例代码，深入探讨Go语言中哪些值是可寻址的，哪些值是不可寻址的，并解释其背后的原理。&lt;/p&gt;
&lt;h2&gt;示例代码解析&lt;/h2&gt;
&lt;p&gt;以下是我们将要解析的示例代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

type Named interface {
	// Name 用于获取名字。
	Name() string
}

type Dog struct {
	name string
}

func (dog *Dog) SetName(name string) {
	dog.name = name
}

func (dog Dog) Name() string {
	return dog.name
}

func main() {
	// 示例1。
	const num = 123
	//_ = &amp;amp;num // 常量不可寻址。
	//_ = &amp;amp;(123) // 基本类型值的字面量不可寻址。

	var str = &quot;abc&quot;
	_ = str
	//_ = &amp;amp;(str[0]) // 对字符串变量的索引结果值不可寻址。
	//_ = &amp;amp;(str[0:2]) // 对字符串变量的切片结果值不可寻址。
	str2 := str[0]
	_ = &amp;amp;str2 // 但这样的寻址就是合法的。

	//_ = &amp;amp;(123 + 456) // 算术操作的结果值不可寻址。
	num2 := 456
	_ = num2
	//_ = &amp;amp;(num + num2) // 算术操作的结果值不可寻址。

	//_ = &amp;amp;([3]int{1, 2, 3}[0]) // 对数组字面量的索引结果值不可寻址。
	//_ = &amp;amp;([3]int{1, 2, 3}[0:2]) // 对数组字面量的切片结果值不可寻址。
	_ = &amp;amp;([]int{1, 2, 3}[0]) // 对切片字面量的索引结果值却是可寻址的。
	//_ = &amp;amp;([]int{1, 2, 3}[0:2]) // 对切片字面量的切片结果值不可寻址。
	//_ = &amp;amp;(map[int]string{1: &quot;a&quot;}[0]) // 对字典字面量的索引结果值不可寻址。

	var map1 = map[int]string{1: &quot;a&quot;, 2: &quot;b&quot;, 3: &quot;c&quot;}
	_ = map1
	//_ = &amp;amp;(map1[2]) // 对字典变量的索引结果值不可寻址。

	//_ = &amp;amp;(func(x, y int) int {
	//	return x + y
	//}) // 字面量代表的函数不可寻址。
	//_ = &amp;amp;(fmt.Sprintf) // 标识符代表的函数不可寻址。
	//_ = &amp;amp;(fmt.Sprintln(&quot;abc&quot;)) // 对函数的调用结果值不可寻址。

	dog := Dog{&quot;little pig&quot;}
	_ = dog
	//_ = &amp;amp;(dog.Name) // 标识符代表的函数不可寻址。
	//_ = &amp;amp;(dog.Name()) // 对方法的调用结果值不可寻址。

	//_ = &amp;amp;(Dog{&quot;little pig&quot;}.name) // 结构体字面量的字段不可寻址。

	//_ = &amp;amp;(interface{}(dog)) // 类型转换表达式的结果值不可寻址。
	dogI := interface{}(dog)
	_ = dogI
	//_ = &amp;amp;(dogI.(Named)) // 类型断言表达式的结果值不可寻址。
	named := dogI.(Named)
	_ = named
	//_ = &amp;amp;(named.(Dog)) // 类型断言表达式的结果值不可寻址。

	var chan1 = make(chan int, 1)
	chan1 &amp;lt;- 1
	//_ = &amp;amp;(&amp;lt;-chan1) // 接收表达式的结果值不可寻址。
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;不可寻址值的分类&lt;/h2&gt;
&lt;h3&gt;1. 常量和字面量&lt;/h3&gt;
&lt;p&gt;常量和字面量是不可寻址的，因为它们在编译时就已经确定了值，且没有内存地址。例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const num = 123
//_ = &amp;amp;num // 常量不可寻址。
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 基本类型值的字面量&lt;/h3&gt;
&lt;p&gt;基本类型值的字面量也是不可寻址的，因为它们没有分配内存地址：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;//_ = &amp;amp;(123) // 基本类型值的字面量不可寻址。
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 字符串索引和切片结果&lt;/h3&gt;
&lt;p&gt;字符串的索引和切片结果值不可寻址，因为字符串是不可变的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var str = &quot;abc&quot;
//_ = &amp;amp;(str[0]) // 对字符串变量的索引结果值不可寻址。
//_ = &amp;amp;(str[0:2]) // 对字符串变量的切片结果值不可寻址。
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. 算术操作的结果&lt;/h3&gt;
&lt;p&gt;算术操作的结果值不可寻址，因为它们是临时值，没有分配内存地址：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;//_ = &amp;amp;(123 + 456) // 算术操作的结果值不可寻址。
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5. 数组字面量的索引和切片结果&lt;/h3&gt;
&lt;p&gt;数组字面量的索引和切片结果值不可寻址，因为它们是临时值：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;//_ = &amp;amp;([3]int{1, 2, 3}[0]) // 对数组字面量的索引结果值不可寻址。
//_ = &amp;amp;([3]int{1, 2, 3}[0:2]) // 对数组字面量的切片结果值不可寻址。
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;6. 字典变量的索引结果&lt;/h3&gt;
&lt;p&gt;字典变量的索引结果值不可寻址，因为字典的实现细节使得其值的地址不固定：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var map1 = map[int]string{1: &quot;a&quot;, 2: &quot;b&quot;, 3: &quot;c&quot;}
//_ = &amp;amp;(map1[2]) // 对字典变量的索引结果值不可寻址。
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;7. 函数字面量和调用结果&lt;/h3&gt;
&lt;p&gt;函数字面量和调用结果值不可寻址，因为它们是临时值：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;//_ = &amp;amp;(func(x, y int) int {
//	return x + y
//}) // 字面量代表的函数不可寻址。
//_ = &amp;amp;(fmt.Sprintf) // 标识符代表的函数不可寻址。
//_ = &amp;amp;(fmt.Sprintln(&quot;abc&quot;)) // 对函数的调用结果值不可寻址。
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;8. 结构体字面量的字段&lt;/h3&gt;
&lt;p&gt;结构体字面量的字段不可寻址，因为它们是临时值：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;//_ = &amp;amp;(Dog{&quot;little pig&quot;}.name) // 结构体字面量的字段不可寻址。
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;9. 类型转换和断言结果&lt;/h3&gt;
&lt;p&gt;类型转换和断言结果值不可寻址，因为它们是临时值：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;//_ = &amp;amp;(interface{}(dog)) // 类型转换表达式的结果值不可寻址。
dogI := interface{}(dog)
//_ = &amp;amp;(dogI.(Named)) // 类型断言表达式的结果值不可寻址。
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;10. 接收表达式的结果&lt;/h3&gt;
&lt;p&gt;接收表达式的结果值不可寻址，因为它们是临时值：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var chan1 = make(chan int, 1)
chan1 &amp;lt;- 1
//_ = &amp;amp;(&amp;lt;-chan1) // 接收表达式的结果值不可寻址。
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;可寻址值的例外&lt;/h2&gt;
&lt;p&gt;尽管大多数情况下上述值是不可寻址的，但也有一些例外情况。例如，对切片字面量的索引结果值是可寻址的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;_ = &amp;amp;([]int{1, 2, 3}[0]) // 对切片字面量的索引结果值却是可寻址的。
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;理解值的可寻址性对于编写高效的Go代码至关重要。通过上述示例和解释，我们可以更好地理解哪些值是可寻址的，哪些值是不可寻址的，以及其背后的原因。希望这篇教程能帮助你在Go语言编程中更加得心应手。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：Go语言中的接口和面向对象设计</title><link>https://blog.ithuo.net/posts/go-tutorial-interface-struct-oop/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-tutorial-interface-struct-oop/</guid><pubDate>Fri, 13 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在本教程中，我们将探讨Go语言中的接口（interface）以及如何使用接口实现面向对象的设计思想。接口是Go语言中一个非常重要和强大的特性，它允许我们定义对象的行为，而不关心具体的实现细节。&lt;/p&gt;
&lt;h2&gt;接口的定义和实现&lt;/h2&gt;
&lt;p&gt;在Go语言中，接口是一组方法签名的集合。一个类型只需要实现接口中定义的所有方法，就可以被认为是实现了该接口。下面是一个简单的接口定义示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Animal interface {
    ScientificName() string
    Category() string
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个例子中，我们定义了一个&lt;code&gt;Animal&lt;/code&gt;接口，它包含了两个方法：&lt;code&gt;ScientificName()&lt;/code&gt;和&lt;code&gt;Category()&lt;/code&gt;。任何实现了这两个方法的类型都可以被认为是一个&lt;code&gt;Animal&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;让我们定义一个&lt;code&gt;Dog&lt;/code&gt;结构体，并为其实现&lt;code&gt;Animal&lt;/code&gt;接口：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Dog struct {
    scientificName string
}

func (dog Dog) ScientificName() string {
    return dog.scientificName
}

func (dog Dog) Category() string {
    return &quot;dog&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这里，&lt;code&gt;Dog&lt;/code&gt;结构体实现了&lt;code&gt;Animal&lt;/code&gt;接口的两个方法，因此它可以被视为一个&lt;code&gt;Animal&lt;/code&gt;类型。&lt;/p&gt;
&lt;h2&gt;接口值的nil判断&lt;/h2&gt;
&lt;p&gt;在Go语言中，将一个&lt;code&gt;nil&lt;/code&gt;指针赋值给接口类型的变量时，接口变量的值不为&lt;code&gt;nil&lt;/code&gt;，而是一个包含了&lt;code&gt;nil&lt;/code&gt;指针的接口值。这一点与其他语言（如Java）有所不同，需要特别注意。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var dog1 *Dog = nil
var animal Animal = dog1
if animal == nil {
    fmt.Println(&quot;The animal is nil.&quot;)
} else {
    fmt.Println(&quot;The animal is not nil.&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个例子中，尽管&lt;code&gt;dog1&lt;/code&gt;是&lt;code&gt;nil&lt;/code&gt;，但&lt;code&gt;animal&lt;/code&gt;并不是&lt;code&gt;nil&lt;/code&gt;。因为&lt;code&gt;animal&lt;/code&gt;是一个接口类型的变量，它的值是一个包含了&lt;code&gt;nil&lt;/code&gt;指针的接口值。&lt;/p&gt;
&lt;h2&gt;接口的嵌套和组合&lt;/h2&gt;
&lt;p&gt;Go语言中的接口支持嵌套和组合，这使得我们可以更加灵活地设计和重用接口。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Named interface {
    Name() string
}

type Pet interface {
    Animal
    Named
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个例子中，我们定义了两个接口：&lt;code&gt;Named&lt;/code&gt;和&lt;code&gt;Pet&lt;/code&gt;。其中，&lt;code&gt;Pet&lt;/code&gt;接口嵌套了&lt;code&gt;Animal&lt;/code&gt;和&lt;code&gt;Named&lt;/code&gt;接口，表示一个&lt;code&gt;Pet&lt;/code&gt;类型需要同时实现&lt;code&gt;Animal&lt;/code&gt;和&lt;code&gt;Named&lt;/code&gt;接口的所有方法。&lt;/p&gt;
&lt;p&gt;我们可以定义一个&lt;code&gt;PetTag&lt;/code&gt;结构体，并为其实现&lt;code&gt;Named&lt;/code&gt;接口：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type PetTag struct {
    name string
}

func (pt PetTag) Name() string {
    return pt.name
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后，我们可以在&lt;code&gt;Dog&lt;/code&gt;结构体中嵌套&lt;code&gt;PetTag&lt;/code&gt;，使其自动继承&lt;code&gt;Named&lt;/code&gt;接口的实现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Dog struct {
    PetTag
    scientificName string
}

func (dog Dog) ScientificName() string {
    return dog.scientificName
}

func (dog Dog) Category() string {
    return &quot;dog&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在，&lt;code&gt;Dog&lt;/code&gt;结构体不仅实现了&lt;code&gt;Animal&lt;/code&gt;接口，还通过嵌套&lt;code&gt;PetTag&lt;/code&gt;实现了&lt;code&gt;Named&lt;/code&gt;接口。因此，&lt;code&gt;Dog&lt;/code&gt;也实现了&lt;code&gt;Pet&lt;/code&gt;接口。&lt;/p&gt;
&lt;h2&gt;接口与面向对象设计&lt;/h2&gt;
&lt;p&gt;Go语言中的接口与面向对象设计中的抽象类和接口概念类似。它们都允许我们定义对象的行为，而不关心具体的实现细节。&lt;/p&gt;
&lt;p&gt;通过使用接口，我们可以实现以下面向对象设计的原则：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;封装：接口定义了对象的行为，隐藏了内部实现细节。&lt;/li&gt;
&lt;li&gt;继承：通过接口嵌套和结构体嵌套，我们可以实现接口和类型的继承关系。&lt;/li&gt;
&lt;li&gt;多态：不同的类型可以实现同一个接口，从而实现多态的行为。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;下面是一个多态的例子：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func PlayWithPet(pet Pet) {
    fmt.Printf(&quot;Playing with pet: %s\\n&quot;, pet.Name())
    fmt.Printf(&quot;Scientific name: %s\\n&quot;, pet.ScientificName())
    fmt.Printf(&quot;Category: %s\\n&quot;, pet.Category())
}

func main() {
    dog := Dog{
        PetTag:         PetTag{name: &quot;Buddy&quot;},
        scientificName: &quot;Canis lupus familiaris&quot;,
    }
    PlayWithPet(dog)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个例子中，&lt;code&gt;PlayWithPet&lt;/code&gt;函数接受一个&lt;code&gt;Pet&lt;/code&gt;接口类型的参数。由于&lt;code&gt;Dog&lt;/code&gt;实现了&lt;code&gt;Pet&lt;/code&gt;接口，我们可以将&lt;code&gt;dog&lt;/code&gt;实例传递给&lt;code&gt;PlayWithPet&lt;/code&gt;函数，实现了多态的行为。&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;在本教程中，我们学习了Go语言中接口的定义、实现、嵌套和组合，以及如何使用接口实现面向对象设计的原则。接口是Go语言中一个非常强大和灵活的特性，通过合理地使用接口，我们可以编写出更加模块化、可扩展和可维护的代码。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：深入理解接口与结构体 2</title><link>https://blog.ithuo.net/posts/go-tutorial-interface-struct-2/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-tutorial-interface-struct-2/</guid><pubDate>Thu, 12 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;介绍&lt;/h3&gt;
&lt;p&gt;在Go语言中，接口（interface）和结构体（struct）是构建灵活和可扩展程序的基础。接口定义了一组方法，而结构体可以实现这些方法，从而实现接口。&lt;/p&gt;
&lt;h3&gt;示例代码&lt;/h3&gt;
&lt;p&gt;以下是一个完整的Go语言代码示例，展示了如何定义接口、结构体以及实现接口的方法：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import &quot;fmt&quot;

type Pet interface {
	SetName(name string)
	Name() string
	Category() string
}

type Dog struct {
	name string // 名字。
}

func (dog *Dog) SetName(name string) {
	dog.name = name
}

func (dog Dog) Name() string {
	return dog.name
}

func (dog Dog) Category() string {
	return &quot;dog&quot;
}

func main() {
	// 示例1。
	dog := Dog{&quot;little pig&quot;}
	_, ok := interface{}(dog).(Pet)
	fmt.Printf(&quot;Dog implements interface Pet: %v\\n&quot;, ok)
	_, ok = interface{}(&amp;amp;dog).(Pet)
	fmt.Printf(&quot;*Dog implements interface Pet: %v\\n&quot;, ok)
	fmt.Println()

	// 示例2。
	var pet Pet = &amp;amp;dog
	fmt.Printf(&quot;This pet is a %s, the name is %q.\\n&quot;,
		pet.Category(), pet.Name())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;代码解析&lt;/h3&gt;
&lt;h3&gt;定义接口&lt;/h3&gt;
&lt;p&gt;首先，我们定义了一个 &lt;code&gt;Pet&lt;/code&gt; 接口，接口中包含三个方法：&lt;code&gt;SetName&lt;/code&gt;、&lt;code&gt;Name&lt;/code&gt; 和 &lt;code&gt;Category&lt;/code&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Pet interface {
	SetName(name string)
	Name() string
	Category() string
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;定义结构体&lt;/h3&gt;
&lt;p&gt;接下来，我们定义了一个 &lt;code&gt;Dog&lt;/code&gt; 结构体，用于表示狗的基本信息，包括名字。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Dog struct {
	name string // 名字。
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;实现接口方法&lt;/h3&gt;
&lt;p&gt;我们为 &lt;code&gt;Dog&lt;/code&gt; 结构体实现了 &lt;code&gt;Pet&lt;/code&gt; 接口中的方法。需要注意的是，&lt;code&gt;SetName&lt;/code&gt; 方法接收一个指向 &lt;code&gt;Dog&lt;/code&gt; 结构体的指针，这意味着它可以修改原始结构体的内容。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func (dog *Dog) SetName(name string) {
	dog.name = name
}

func (dog Dog) Name() string {
	return dog.name
}

func (dog Dog) Category() string {
	return &quot;dog&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;主函数&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;main&lt;/code&gt; 函数中，我们创建了一个 &lt;code&gt;Dog&lt;/code&gt; 实例，并检查 &lt;code&gt;Dog&lt;/code&gt; 结构体和 &lt;code&gt;*Dog&lt;/code&gt; 指针是否实现了 &lt;code&gt;Pet&lt;/code&gt; 接口。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func main() {
	// 示例1。
	dog := Dog{&quot;little pig&quot;}
	_, ok := interface{}(dog).(Pet)
	fmt.Printf(&quot;Dog implements interface Pet: %v\\n&quot;, ok)
	_, ok = interface{}(&amp;amp;dog).(Pet)
	fmt.Printf(&quot;*Dog implements interface Pet: %v\\n&quot;, ok)
	fmt.Println()

	// 示例2。
	var pet Pet = &amp;amp;dog
	fmt.Printf(&quot;This pet is a %s, the name is %q.\\n&quot;,
		pet.Category(), pet.Name())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;运行结果&lt;/h3&gt;
&lt;p&gt;运行上述代码，输出结果如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Dog implements interface Pet: false
*Dog implements interface Pet: true

This pet is a dog, the name is &quot;little pig&quot;.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;举一反三&lt;/h3&gt;
&lt;p&gt;通过这个示例，我们可以举一反三地应用这些概念。例如，我们可以定义一个 &lt;code&gt;Cat&lt;/code&gt; 结构体，并实现类似的方法和接口：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Cat struct {
	name string
}

func (cat *Cat) SetName(name string) {
	cat.name = name
}

func (cat Cat) Name() string {
	return cat.name
}

func (cat Cat) Category() string {
	return &quot;cat&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后，我们可以在 &lt;code&gt;main&lt;/code&gt; 函数中创建 &lt;code&gt;Cat&lt;/code&gt; 实例，并检查其行为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func main() {
	// 示例1。
	cat := Cat{&quot;whiskers&quot;}
	_, ok := interface{}(cat).(Pet)
	fmt.Printf(&quot;Cat implements interface Pet: %v\\n&quot;, ok)
	_, ok = interface{}(&amp;amp;cat).(Pet)
	fmt.Printf(&quot;*Cat implements interface Pet: %v\\n&quot;, ok)
	fmt.Println()

	// 示例2。
	var pet Pet = &amp;amp;cat
	fmt.Printf(&quot;This pet is a %s, the name is %q.\\n&quot;,
		pet.Category(), pet.Name())
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;通过这个教程，我们深入探讨了Go语言中的接口和结构体，并展示了如何举一反三地应用这些概念。理解这些基础知识将帮助你在Go语言中构建更复杂和灵活的程序。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：深入探究结构体、方法和接口</title><link>https://blog.ithuo.net/posts/go-tutorial-struct-method-interface/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-tutorial-struct-method-interface/</guid><pubDate>Wed, 11 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;介绍&lt;/h3&gt;
&lt;p&gt;在Go语言中，结构体（struct）、方法和接口是构建复杂数据模型和实现多态行为的基础。本文将通过一个具体的代码示例，深入探究这些概念，并展示如何举一反三地应用它们。&lt;/p&gt;
&lt;h3&gt;示例代码&lt;/h3&gt;
&lt;p&gt;以下是一个完整的Go语言代码示例，展示了如何定义结构体、方法以及接口：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import &quot;fmt&quot;

type Cat struct {
	name           string // 名字。
	scientificName string // 学名。
	category       string // 动物学基本分类。
}

func New(name, scientificName, category string) Cat {
	return Cat{
		name:           name,
		scientificName: scientificName,
		category:       category,
	}
}

func (cat *Cat) SetName(name string) {
	cat.name = name
}

func (cat Cat) SetNameOfCopy(name string) {
	cat.name = name
}

func (cat Cat) Name() string {
	return cat.name
}

func (cat Cat) ScientificName() string {
	return cat.scientificName
}

func (cat Cat) Category() string {
	return cat.category
}

func (cat Cat) String() string {
	return fmt.Sprintf(&quot;%s (category: %s, name: %q)&quot;,
		cat.scientificName, cat.category, cat.name)
}

func main() {
	cat := New(&quot;little pig&quot;, &quot;American Shorthair&quot;, &quot;cat&quot;)
	cat.SetName(&quot;monster&quot;) // (&amp;amp;cat).SetName(&quot;monster&quot;)
	fmt.Printf(&quot;The cat: %s\\n&quot;, cat)

	cat.SetNameOfCopy(&quot;little pig&quot;)
	fmt.Printf(&quot;The cat: %s\\n&quot;, cat)

	type Pet interface {
		SetName(name string)
		Name() string
		Category() string
		ScientificName() string
	}

	_, ok := interface{}(cat).(Pet)
	fmt.Printf(&quot;Cat implements interface Pet: %v\\n&quot;, ok)
	_, ok = interface{}(&amp;amp;cat).(Pet)
	fmt.Printf(&quot;*Cat implements interface Pet: %v\\n&quot;, ok)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;代码解析&lt;/h3&gt;
&lt;h3&gt;定义结构体&lt;/h3&gt;
&lt;p&gt;首先，我们定义了一个 &lt;code&gt;Cat&lt;/code&gt; 结构体，用于表示猫的基本信息，包括名字、学名和分类。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Cat struct {
	name           string // 名字。
	scientificName string // 学名。
	category       string // 动物学基本分类。
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;构造函数&lt;/h3&gt;
&lt;p&gt;接下来，我们定义了一个构造函数 &lt;code&gt;New&lt;/code&gt;，用于创建 &lt;code&gt;Cat&lt;/code&gt; 结构体的实例。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func New(name, scientificName, category string) Cat {
	return Cat{
		name:           name,
		scientificName: scientificName,
		category:       category,
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;方法定义&lt;/h3&gt;
&lt;p&gt;我们为 &lt;code&gt;Cat&lt;/code&gt; 结构体定义了一些方法，包括设置名字、获取名字、获取学名和获取分类的方法。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func (cat *Cat) SetName(name string) {
	cat.name = name
}

func (cat Cat) SetNameOfCopy(name string) {
	cat.name = name
}

func (cat Cat) Name() string {
	return cat.name
}

func (cat Cat) ScientificName() string {
	return cat.scientificName
}

func (cat Cat) Category() string {
	return cat.category
}

func (cat Cat) String() string {
	return fmt.Sprintf(&quot;%s (category: %s, name: %q)&quot;,
		cat.scientificName, cat.category, cat.name)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要注意的是，&lt;code&gt;SetName&lt;/code&gt; 方法接收一个指向 &lt;code&gt;Cat&lt;/code&gt; 结构体的指针，这意味着它可以修改原始结构体的内容。而 &lt;code&gt;SetNameOfCopy&lt;/code&gt; 方法接收的是结构体的值，这意味着它只能修改副本的内容，不会影响原始结构体。&lt;/p&gt;
&lt;h3&gt;主函数&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;main&lt;/code&gt; 函数中，我们创建了一个 &lt;code&gt;Cat&lt;/code&gt; 实例，并调用了不同的方法来展示其行为。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func main() {
	cat := New(&quot;little pig&quot;, &quot;American Shorthair&quot;, &quot;cat&quot;)
	cat.SetName(&quot;monster&quot;) // (&amp;amp;cat).SetName(&quot;monster&quot;)
	fmt.Printf(&quot;The cat: %s\\n&quot;, cat)

	cat.SetNameOfCopy(&quot;little pig&quot;)
	fmt.Printf(&quot;The cat: %s\\n&quot;, cat)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;接口实现&lt;/h3&gt;
&lt;p&gt;我们定义了一个 &lt;code&gt;Pet&lt;/code&gt; 接口，并检查 &lt;code&gt;Cat&lt;/code&gt; 结构体和 &lt;code&gt;*Cat&lt;/code&gt; 指针是否实现了该接口。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Pet interface {
		SetName(name string)
		Name() string
		Category() string
		ScientificName() string
	}

	_, ok := interface{}(cat).(Pet)
	fmt.Printf(&quot;Cat implements interface Pet: %v\\n&quot;, ok)
	_, ok = interface{}(&amp;amp;cat).(Pet)
	fmt.Printf(&quot;*Cat implements interface Pet: %v\\n&quot;, ok)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;运行结果&lt;/h3&gt;
&lt;p&gt;运行上述代码，输出结果如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;The cat: American Shorthair (category: cat, name: &quot;monster&quot;)
The cat: American Shorthair (category: cat, name: &quot;monster&quot;)
Cat implements interface Pet: false
*Cat implements interface Pet: true
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;举一反三&lt;/h3&gt;
&lt;p&gt;通过这个示例，我们可以举一反三地应用这些概念。例如，我们可以定义一个 &lt;code&gt;Dog&lt;/code&gt; 结构体，并实现类似的方法和接口：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Dog struct {
	name           string
	scientificName string
	category       string
}

func NewDog(name, scientificName, category string) Dog {
	return Dog{
		name:           name,
		scientificName: scientificName,
		category:       category,
	}
}

func (dog *Dog) SetName(name string) {
	dog.name = name
}

func (dog Dog) Name() string {
	return dog.name
}

func (dog Dog) ScientificName() string {
	return dog.scientificName
}

func (dog Dog) Category() string {
	return dog.category
}

func (dog Dog) String() string {
	return fmt.Sprintf(&quot;%s (category: %s, name: %q)&quot;,
		dog.scientificName, dog.category, dog.name)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后，我们可以在 &lt;code&gt;main&lt;/code&gt; 函数中创建 &lt;code&gt;Dog&lt;/code&gt; 实例，并检查其行为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func main() {
	dog := NewDog(&quot;buddy&quot;, &quot;Canis lupus familiaris&quot;, &quot;dog&quot;)
	dog.SetName(&quot;max&quot;)
	fmt.Printf(&quot;The dog: %s\\n&quot;, dog)

	type Pet interface {
		SetName(name string)
		Name() string
		Category() string
		ScientificName() string
	}

	_, ok := interface{}(dog).(Pet)
	fmt.Printf(&quot;Dog implements interface Pet: %v\\n&quot;, ok)
	_, ok = interface{}(&amp;amp;dog).(Pet)
	fmt.Printf(&quot;*Dog implements interface Pet: %v\\n&quot;, ok)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;通过这个教程，我们深入探讨了Go语言中的结构体、方法和接口，并展示了如何举一反三地应用这些概念。理解这些基础知识将帮助你在Go语言中构建更复杂和灵活的程序。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：深入浅出理解结构体嵌套与方法重写</title><link>https://blog.ithuo.net/posts/go-tutorial-struct-nesting-method-overriding/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-tutorial-struct-nesting-method-overriding/</guid><pubDate>Tue, 10 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;介绍&lt;/h3&gt;
&lt;p&gt;在Go语言中，结构体（struct）是一个非常重要的数据类型，它允许我们将不同类型的数据组合在一起。通过嵌套结构体和方法重写，我们可以实现更复杂的数据模型和行为。本文将通过一个具体的代码示例，深入浅出地介绍这些概念。&lt;/p&gt;
&lt;h3&gt;示例代码&lt;/h3&gt;
&lt;p&gt;以下是一个完整的Go语言代码示例，展示了如何使用结构体嵌套和方法重写：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import &quot;fmt&quot;

// 示例1。
// AnimalCategory 代表动物分类学中的基本分类法。
type AnimalCategory struct {
	kingdom string // 界。
	phylum  string // 门。
	class   string // 纲。
	order   string // 目。
	family  string // 科。
	genus   string // 属。
	species string // 种。
}

func (ac AnimalCategory) String() string {
	return fmt.Sprintf(&quot;%s%s%s%s%s%s%s&quot;,
		ac.kingdom, ac.phylum, ac.class, ac.order,
		ac.family, ac.genus, ac.species)
}

// 示例2。
type Animal struct {
	scientificName string // 学名。
	AnimalCategory        // 动物基本分类。
}

// 该方法会&quot;屏蔽&quot;掉嵌入字段中的同名方法。
func (a Animal) String() string {
	return fmt.Sprintf(&quot;%s (category: %s)&quot;,
		a.scientificName, a.AnimalCategory)
}

// 示例3。
type Cat struct {
	name string
	Animal
}

// 该方法会&quot;屏蔽&quot;掉嵌入字段中的同名方法。
func (cat Cat) String() string {
	return fmt.Sprintf(&quot;%s (category1: %s, name: %q)&quot;,
		cat.scientificName, cat.Animal.AnimalCategory, cat.name)
}

func main() {
	// 示例1。
	category := AnimalCategory{species: &quot;cat&quot;}
	fmt.Printf(&quot;The animal category: %s\\n&quot;, category)

	// 示例2。
	animal := Animal{
		scientificName: &quot;American Shorthair&quot;,
		AnimalCategory: category,
	}
	fmt.Printf(&quot;The animal: %s\\n&quot;, animal)

	// 示例3。
	cat := Cat{
		name:   &quot;little pig&quot;,
		Animal: animal,
	}
	fmt.Printf(&quot;The cat: %s\\n&quot;, cat)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;代码解析&lt;/h3&gt;
&lt;h3&gt;示例1：基本结构体&lt;/h3&gt;
&lt;p&gt;首先，我们定义了一个 &lt;code&gt;AnimalCategory&lt;/code&gt; 结构体，用于表示动物分类学中的基本分类法。这个结构体包含了多个字段，如 &lt;code&gt;kingdom&lt;/code&gt;（界）、&lt;code&gt;phylum&lt;/code&gt;（门）、&lt;code&gt;class&lt;/code&gt;（纲）等。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type AnimalCategory struct {
	kingdom string // 界。
	phylum  string // 门。
	class   string // 纲。
	order   string // 目。
	family  string // 科。
	genus   string // 属。
	species string // 种。
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们还为 &lt;code&gt;AnimalCategory&lt;/code&gt; 结构体定义了一个 &lt;code&gt;String&lt;/code&gt; 方法，用于返回该结构体的字符串表示。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func (ac AnimalCategory) String() string {
	return fmt.Sprintf(&quot;%s%s%s%s%s%s%s&quot;,
		ac.kingdom, ac.phylum, ac.class, ac.order,
		ac.family, ac.genus, ac.species)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;示例2：嵌套结构体&lt;/h3&gt;
&lt;p&gt;接下来，我们定义了一个 &lt;code&gt;Animal&lt;/code&gt; 结构体，它嵌套了 &lt;code&gt;AnimalCategory&lt;/code&gt; 结构体，并添加了一个 &lt;code&gt;scientificName&lt;/code&gt; 字段。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Animal struct {
	scientificName string // 学名。
	AnimalCategory        // 动物基本分类。
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同样，我们为 &lt;code&gt;Animal&lt;/code&gt; 结构体定义了一个 &lt;code&gt;String&lt;/code&gt; 方法，这个方法会“屏蔽”掉嵌入字段中的同名方法。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func (a Animal) String() string {
	return fmt.Sprintf(&quot;%s (category: %s)&quot;,
		a.scientificName, a.AnimalCategory)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;示例3：进一步嵌套&lt;/h3&gt;
&lt;p&gt;最后，我们定义了一个 &lt;code&gt;Cat&lt;/code&gt; 结构体，它嵌套了 &lt;code&gt;Animal&lt;/code&gt; 结构体，并添加了一个 &lt;code&gt;name&lt;/code&gt; 字段。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Cat struct {
	name string
	Animal
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同样，我们为 &lt;code&gt;Cat&lt;/code&gt; 结构体定义了一个 &lt;code&gt;String&lt;/code&gt; 方法，这个方法会“屏蔽”掉嵌入字段中的同名方法。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func (cat Cat) String() string {
	return fmt.Sprintf(&quot;%s (category1: %s, name: %q)&quot;,
		cat.scientificName, cat.Animal.AnimalCategory, cat.name)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;运行结果&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;main&lt;/code&gt; 函数中，我们创建了 &lt;code&gt;AnimalCategory&lt;/code&gt;、&lt;code&gt;Animal&lt;/code&gt; 和 &lt;code&gt;Cat&lt;/code&gt; 的实例，并打印它们的字符串表示。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func main() {
	// 示例1。
	category := AnimalCategory{species: &quot;cat&quot;}
	fmt.Printf(&quot;The animal category: %s\\n&quot;, category)

	// 示例2。
	animal := Animal{
		scientificName: &quot;American Shorthair&quot;,
		AnimalCategory: category,
	}
	fmt.Printf(&quot;The animal: %s\\n&quot;, animal)

	// 示例3。
	cat := Cat{
		name:   &quot;little pig&quot;,
		Animal: animal,
	}
	fmt.Printf(&quot;The cat: %s\\n&quot;, cat)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行结果如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;The animal category: cat
The animal: American Shorthair (category: cat)
The cat: American Shorthair (category1: cat, name: &quot;little pig&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;通过这个示例，我们展示了如何在Go语言中使用结构体嵌套和方法重写。结构体嵌套使得我们可以创建更复杂的数据模型，而方法重写则允许我们为不同的结构体定义特定的行为。这些特性使得Go语言在处理复杂数据结构时非常灵活和强大。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言中的高阶函数与错误处理</title><link>https://blog.ithuo.net/posts/go-higher-order-functions-error-handling/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-higher-order-functions-error-handling/</guid><pubDate>Mon, 09 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在Go语言中，高阶函数和错误处理是两个非常重要的概念。本文将通过一个简单的示例代码，详细讲解这两个概念的应用和扩展。&lt;/p&gt;
&lt;h3&gt;示例代码&lt;/h3&gt;
&lt;p&gt;以下是一个简单的Go语言程序，展示了如何使用高阶函数和错误处理：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;errors&quot;
	&quot;fmt&quot;
)

type operate func(x, y int) int

// 方案1。
func calculate(x int, y int, op operate) (int, error) {
	if op == nil {
		return 0, errors.New(&quot;invalid operation&quot;)
	}
	return op(x, y), nil
}

// 方案2。
type calculateFunc func(x int, y int) (int, error)

func genCalculator(op operate) calculateFunc {
	return func(x int, y int) (int, error) {
		if op == nil {
			return 0, errors.New(&quot;invalid operation&quot;)
		}
		return op(x, y), nil
	}
}

func main() {
	// 方案1。
	x, y := 12, 23
	op := func(x, y int) int {
		return x + y
	}
	result, err := calculate(x, y, op)
	fmt.Printf(&quot;The result: %d (error: %v)\\n&quot;, result, err)
	result, err = calculate(x, y, nil)
	fmt.Printf(&quot;The result: %d (error: %v)\\n&quot;, result, err)

	// 方案2。
	x, y = 56, 78
	add := genCalculator(op)
	result, err = add(x, y)
	fmt.Printf(&quot;The result: %d (error: %v)\\n&quot;, result, err)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;方案1：直接传递函数作为参数&lt;/h3&gt;
&lt;p&gt;在方案1中，我们定义了一个&lt;code&gt;operate&lt;/code&gt;类型，它是一个函数类型，接受两个整数参数并返回一个整数。&lt;code&gt;calculate&lt;/code&gt;函数接受两个整数和一个&lt;code&gt;operate&lt;/code&gt;类型的函数作为参数，并返回计算结果和可能的错误。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func calculate(x int, y int, op operate) (int, error) {
	if op == nil {
		return 0, errors.New(&quot;invalid operation&quot;)
	}
	return op(x, y), nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在&lt;code&gt;main&lt;/code&gt;函数中，我们定义了一个简单的加法操作，并将其传递给&lt;code&gt;calculate&lt;/code&gt;函数进行计算。如果传递的操作函数为&lt;code&gt;nil&lt;/code&gt;，则会返回一个错误。&lt;/p&gt;
&lt;h3&gt;方案2：生成计算器函数&lt;/h3&gt;
&lt;p&gt;在方案2中，我们定义了一个&lt;code&gt;calculateFunc&lt;/code&gt;类型，它是一个函数类型，接受两个整数参数并返回一个整数和一个错误。&lt;code&gt;genCalculator&lt;/code&gt;函数接受一个&lt;code&gt;operate&lt;/code&gt;类型的函数，并返回一个&lt;code&gt;calculateFunc&lt;/code&gt;类型的函数。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func genCalculator(op operate) calculateFunc {
	return func(x int, y int) (int, error) {
		if op == nil {
			return 0, errors.New(&quot;invalid operation&quot;)
		}
		return op(x, y), nil
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在&lt;code&gt;main&lt;/code&gt;函数中，我们使用&lt;code&gt;genCalculator&lt;/code&gt;函数生成一个加法计算器，并使用该计算器进行计算。如果传递的操作函数为&lt;code&gt;nil&lt;/code&gt;，则会返回一个错误。&lt;/p&gt;
&lt;h3&gt;扩展讲解&lt;/h3&gt;
&lt;h3&gt;高阶函数&lt;/h3&gt;
&lt;p&gt;高阶函数是指接受一个或多个函数作为参数，或返回一个函数的函数。在Go语言中，高阶函数可以用于创建更灵活和可重用的代码。例如，在上述代码中，我们通过高阶函数实现了一个通用的计算器，可以根据不同的操作函数执行不同的计算。&lt;/p&gt;
&lt;h3&gt;错误处理&lt;/h3&gt;
&lt;p&gt;在Go语言中，错误处理是通过返回值来实现的。函数可以返回一个错误类型的值，表示函数执行过程中是否发生了错误。在上述代码中，我们通过检查操作函数是否为&lt;code&gt;nil&lt;/code&gt;来判断是否发生了错误，并返回相应的错误信息。&lt;/p&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;本文通过一个简单的示例代码，详细讲解了Go语言中的高阶函数和错误处理的概念和应用。高阶函数使得代码更加灵活和可重用，而错误处理则确保了程序的健壮性和可靠性。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：深入解析通道和选择语句 3</title><link>https://blog.ithuo.net/posts/go-channel-tutorial-3/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-channel-tutorial-3/</guid><pubDate>Sun, 08 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;本文将通过一段代码示例，详细讲解Go语言中的通道（Channel）和选择语句（Select）的使用。我们将逐步解析代码中的每个部分，帮助你更好地理解这些概念。&lt;/p&gt;
&lt;h2&gt;示例代码&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;fmt&quot;
	&quot;math/rand&quot;
	&quot;time&quot;
)

func main() {
	example1()
	example2()
}

// 示例1。
func example1() {
	// 准备好几个通道。
	intChannels := [3]chan int{
		make(chan int, 1),
		make(chan int, 1),
		make(chan int, 1),
	}
	// 随机选择一个通道，并向它发送元素值。
	index := rand.Intn(3)
	fmt.Printf(&quot;The index: %d\\n&quot;, index)
	intChannels[index] &amp;lt;- index
	// 哪一个通道中有可取的元素值，哪个对应的分支就会被执行。
	select {
	case &amp;lt;-intChannels[0]:
		fmt.Println(&quot;The first candidate case is selected.&quot;)
	case &amp;lt;-intChannels[1]:
		fmt.Println(&quot;The second candidate case is selected.&quot;)
	case elem := &amp;lt;-intChannels[2]:
		fmt.Printf(&quot;The third candidate case is selected, the element is %d.\\n&quot;, elem)
	default:
		fmt.Println(&quot;No candidate case is selected!&quot;)
	}
}

// 示例2。
func example2() {
	intChan := make(chan int, 1)
	// 一秒后关闭通道。
	time.AfterFunc(time.Second, func() {
		close(intChan)
	})
	select {
	case _, ok := &amp;lt;-intChan:
		if !ok {
			fmt.Println(&quot;The candidate case is closed.&quot;)
			break
		}
		fmt.Println(&quot;The candidate case is selected.&quot;)
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;示例1：使用 &lt;code&gt;select&lt;/code&gt; 语句选择通道&lt;/h2&gt;
&lt;h3&gt;代码解析&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;example1&lt;/code&gt; 函数中，我们创建了一个包含三个通道的数组 &lt;code&gt;intChannels&lt;/code&gt;。每个通道都是带缓冲的，缓冲区大小为1。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;intChannels := [3]chan int{
	make(chan int, 1),
	make(chan int, 1),
	make(chan int, 1),
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接下来，我们随机选择一个通道，并向该通道发送一个元素值。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;index := rand.Intn(3)
fmt.Printf(&quot;The index: %d\\n&quot;, index)
intChannels[index] &amp;lt;- index
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后，我们使用 &lt;code&gt;select&lt;/code&gt; 语句来选择哪个通道中有可取的元素值。&lt;code&gt;select&lt;/code&gt; 语句会随机选择一个可用的通道进行操作。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;select {
case &amp;lt;-intChannels[0]:
	fmt.Println(&quot;The first candidate case is selected.&quot;)
case &amp;lt;-intChannels[1]:
	fmt.Println(&quot;The second candidate case is selected.&quot;)
case elem := &amp;lt;-intChannels[2]:
	fmt.Printf(&quot;The third candidate case is selected, the element is %d.\\n&quot;, elem)
default:
	fmt.Println(&quot;No candidate case is selected!&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;运行结果&lt;/h3&gt;
&lt;p&gt;运行结果会根据随机选择的通道不同而有所变化。例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;The index: 1
The second candidate case is selected.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;示例2：通道关闭检测&lt;/h2&gt;
&lt;h3&gt;代码解析&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;example2&lt;/code&gt; 函数中，我们创建了一个带缓冲的通道 &lt;code&gt;intChan&lt;/code&gt;，缓冲区大小为1。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;intChan := make(chan int, 1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们使用 &lt;code&gt;time.AfterFunc&lt;/code&gt; 函数在一秒后关闭该通道。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;time.AfterFunc(time.Second, func() {
	close(intChan)
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接下来，我们使用 &lt;code&gt;select&lt;/code&gt; 语句来检测通道是否关闭。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;select {
case _, ok := &amp;lt;-intChan:
	if !ok {
		fmt.Println(&quot;The candidate case is closed.&quot;)
		break
	}
	fmt.Println(&quot;The candidate case is selected.&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;运行结果&lt;/h3&gt;
&lt;p&gt;由于通道在一秒后关闭，运行结果将会是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;The candidate case is closed.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;通过这两个示例，我们学习了如何使用Go语言中的通道和选择语句。通道用于在不同的Go协程之间传递数据，而选择语句则用于在多个通道操作中进行选择。希望通过本文的讲解，你能更好地理解和应用这些概念。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：通道（Channel）2</title><link>https://blog.ithuo.net/posts/go-channel-tutorial/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-channel-tutorial/</guid><pubDate>Sat, 07 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在Go语言中，通道（Channel）是用于在不同的goroutine之间传递数据的管道。通道在并发编程中非常有用，因为它们提供了一种安全的方式来共享数据。下面我们将详细介绍通道的原理，并通过一个示例代码来说明如何使用通道。&lt;/p&gt;
&lt;h3&gt;通道的基本概念&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;创建通道&lt;/strong&gt;：使用&lt;code&gt;make&lt;/code&gt;函数创建一个通道。通道的类型由其传递的数据类型决定。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ch := make(chan int)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;发送数据&lt;/strong&gt;：使用&lt;code&gt;&amp;lt;-&lt;/code&gt;操作符将数据发送到通道。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ch &amp;lt;- 42
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;接收数据&lt;/strong&gt;：使用&lt;code&gt;&amp;lt;-&lt;/code&gt;操作符从通道接收数据。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;value := &amp;lt;-ch
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;关闭通道&lt;/strong&gt;：使用&lt;code&gt;close&lt;/code&gt;函数关闭通道。关闭后的通道不能再发送数据，但可以继续接收数据，直到通道为空。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;close(ch)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;示例代码解析&lt;/h3&gt;
&lt;p&gt;下面是一个完整的示例代码，展示了如何使用通道在两个goroutine之间传递数据。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import &quot;fmt&quot;

func main() {
    ch1 := make(chan int, 2) // 创建一个缓冲区大小为2的通道

    // 发送方
    go func() {
        for i := 0; i &amp;lt; 10; i++ {
            fmt.Printf(&quot;Sender: sending element %v...\\n&quot;, i)
            ch1 &amp;lt;- i // 将数据发送到通道
        }
        fmt.Println(&quot;Sender: close the channel...&quot;)
        close(ch1) // 发送完数据后关闭通道
    }()

    // 接收方
    for {
        elem, ok := &amp;lt;-ch1 // 从通道接收数据
        if !ok { // 检查通道是否关闭
            fmt.Println(&quot;Receiver: closed channel&quot;)
            break
        }
        fmt.Printf(&quot;Receiver: received an element: %v\\n&quot;, elem)
    }

    fmt.Println(&quot;End.&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;代码详解&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;创建通道&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ch1 := make(chan int, 2)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里我们创建了一个缓冲区大小为2的通道&lt;code&gt;ch1&lt;/code&gt;。缓冲区允许通道在没有接收方的情况下存储最多2个元素。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;发送方goroutine&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go func() {
    for i := 0; i &amp;lt; 10; i++ {
        fmt.Printf(&quot;Sender: sending element %v...\\n&quot;, i)
        ch1 &amp;lt;- i
    }
    fmt.Println(&quot;Sender: close the channel...&quot;)
    close(ch1)
}()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个goroutine负责向通道发送数据。它在循环中发送10个整数到通道&lt;code&gt;ch1&lt;/code&gt;，然后关闭通道。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;接收方&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for {
    elem, ok := &amp;lt;-ch1
    if !ok {
        fmt.Println(&quot;Receiver: closed channel&quot;)
        break
    }
    fmt.Printf(&quot;Receiver: received an element: %v\\n&quot;, elem)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;主goroutine在一个无限循环中从通道接收数据。&lt;code&gt;elem, ok := &amp;lt;-ch1&lt;/code&gt;语句从通道接收数据，并检查通道是否关闭。如果通道关闭，&lt;code&gt;ok&lt;/code&gt;将为&lt;code&gt;false&lt;/code&gt;，循环终止。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;结束程序&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fmt.Println(&quot;End.&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当接收方检测到通道关闭后，程序输出&quot;End.&quot;并结束。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：探索管道（channel）的奇妙世界</title><link>https://blog.ithuo.net/posts/understanding-go-channels/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/understanding-go-channels/</guid><pubDate>Fri, 06 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在这篇教程中，我们将携手探索 Go 语言中管道（channel）的奇妙世界。管道是一种用于同步不同线程或并发程序之间通信的强大机制，帮助你构建更加高效、可靠的程序。&lt;/p&gt;
&lt;h3&gt;1. 管道简介&lt;/h3&gt;
&lt;p&gt;管道就像一条连接两个或多个程序的通道，可以让它们传递数据。数据可以是任何类型，例如数字、字符串、结构体等等。&lt;/p&gt;
&lt;p&gt;创建管道的语法如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ch := make(chan type, bufferSize)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ch&lt;/code&gt; 是管道变量名&lt;/li&gt;
&lt;li&gt;&lt;code&gt;type&lt;/code&gt; 是管道传递的数据类型&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bufferSize&lt;/code&gt; 是可选参数，指定管道的缓冲区大小，默认为 0，表示无缓冲&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 发送数据到管道&lt;/h3&gt;
&lt;p&gt;向管道发送数据可以使用 &lt;code&gt;&amp;lt;-&lt;/code&gt; 操作符，语法如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ch &amp;lt;- data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ch&lt;/code&gt; 是管道变量&lt;/li&gt;
&lt;li&gt;&lt;code&gt;data&lt;/code&gt; 是要发送的数据&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;需要注意的是，如果管道已满，则 &lt;code&gt;&amp;lt;-&lt;/code&gt; 操作会阻塞，直到有足够的空间容纳新数据。&lt;/p&gt;
&lt;h3&gt;3. 从管道接收数据&lt;/h3&gt;
&lt;p&gt;从管道接收数据可以使用 &lt;code&gt;-&amp;gt;&lt;/code&gt; 操作符，语法如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;data := &amp;lt;-ch
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ch&lt;/code&gt; 是管道变量&lt;/li&gt;
&lt;li&gt;&lt;code&gt;data&lt;/code&gt; 用来接收数据的变量&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;需要注意的是，如果管道为空，则 &lt;code&gt;-&amp;gt;&lt;/code&gt; 操作会阻塞，直到有数据可供接收。&lt;/p&gt;
&lt;h3&gt;4. 管道操作示例&lt;/h3&gt;
&lt;p&gt;为了更好地理解管道的工作原理，让我们来看一些示例：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例1：向管道发送和接收数据&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import &quot;fmt&quot;

func main() {
  ch := make(chan int, 3)
  ch &amp;lt;- 2
  ch &amp;lt;- 1
  ch &amp;lt;- 3
  elem1 := &amp;lt;-ch
  fmt.Printf(&quot;The first element received from channel ch1: %v\n&quot;, elem1)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个示例中，我们创建了一个容量为 3 的管道 &lt;code&gt;ch&lt;/code&gt;，并向其中发送了三个整数 2、1、3。然后，我们从管道中接收第一个元素并打印出来。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例2：处理管道阻塞&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import &quot;fmt&quot;

func main() {
  // 示例1。
  ch1 := make(chan int, 1)
  ch1 &amp;lt;- 1
  //ch1 &amp;lt;- 2 // 通道已满，因此这里会造成阻塞。

  // 示例2。
  ch2 := make(chan int, 1)
  //elem, ok := &amp;lt;-ch2 // 通道已空，因此这里会造成阻塞。
  //_, _ = elem, ok
  ch2 &amp;lt;- 1

  // 示例3。
  var ch3 chan int
  //ch3 &amp;lt;- 1 // 通道的值为nil，因此这里会造成永久的阻塞！
  //&amp;lt;-ch3 // 通道的值为nil，因此这里会造成永久的阻塞！
  _ = ch3
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个示例中，我们展示了两种管道阻塞的情况：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;向已满的管道发送数据会导致阻塞&lt;/li&gt;
&lt;li&gt;从空管道接收数据会导致阻塞&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此外，我们还演示了向 nil 管道发送或接收数据的后果，这会导致永久阻塞。&lt;/p&gt;
&lt;h3&gt;5. 总结&lt;/h3&gt;
&lt;p&gt;管道是 Go 语言中一种强大的通信机制，可以帮助你构建更加高效、可靠的并发程序。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：探索 nil map 的世界</title><link>https://blog.ithuo.net/posts/go-nil-map-explained/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-nil-map-explained/</guid><pubDate>Thu, 05 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在这篇教程中，我们将深入探讨 Go 语言中的 nil map，了解它们的特性、常见用法以及潜在陷阱。准备好迎接一段奇妙的旅程吧！&lt;/p&gt;
&lt;h3&gt;1. 认识 nil map&lt;/h3&gt;
&lt;p&gt;nil map 是 Go 语言中表示空 map 的一种特殊值。与其他值不同，nil map 并不指向任何实际的存储空间，而是代表一个不存在的 map。&lt;/p&gt;
&lt;p&gt;通常，我们使用 &lt;code&gt;make(map[key-type]value-type)&lt;/code&gt; 来创建空 map，但 nil map 则是一种更简洁的方式，可以直接赋值 &lt;code&gt;var m map[string]int&lt;/code&gt;。&lt;/p&gt;
&lt;h3&gt;2. 访问 nil map 中的元素&lt;/h3&gt;
&lt;p&gt;正如我们所料，nil map 并不包含任何元素，因此尝试访问其中的元素会引发运行时错误。例如，以下代码会导致 panic：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;key := &quot;two&quot;
elem, ok := m[&quot;two&quot;]
fmt.Println(elem) // panic: key of nil map
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;为了避免错误，我们需要先检查 map 是否为 nil，然后再进行访问。推荐的做法如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if m != nil {
    elem, ok := m[&quot;two&quot;]
    fmt.Println(elem, ok)
} else {
    fmt.Println(&quot;map is nil&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 获取 nil map 的长度&lt;/h3&gt;
&lt;p&gt;nil map 的长度始终为 0，即使你尝试向其中添加元素，也不会改变其长度。以下代码演示了这一点：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fmt.Println(&quot;The length of nil map:&quot;, len(m)) // 0

m[&quot;two&quot;] = 2 // 添加元素

fmt.Println(&quot;The length of nil map:&quot;, len(m)) // 0
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. 删除 nil map 中的元素&lt;/h3&gt;
&lt;p&gt;由于 nil map 根本不包含任何元素，因此删除操作没有任何实际意义，也不会引发错误。以下代码展示了删除 nil map 元素的操作：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fmt.Println(&quot;Delete the key-element pair by key \&quot;two\&quot;...&quot;)
delete(m, &quot;two&quot;)

fmt.Println(&quot;The length of nil map:&quot;, len(m)) // 0
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5. 向 nil map 中添加元素&lt;/h3&gt;
&lt;p&gt;向 nil map 中添加元素的操作看似可以成功，但实际上会导致 panic。这是因为 nil map 并没有分配任何存储空间来容纳新元素。切记要避免此类操作！&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fmt.Println(&quot;Add a key-element pair to a nil map...&quot;)
m[&quot;two&quot;] = 2 // panic: assignment to key of nil map
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;6. 总结&lt;/h3&gt;
&lt;p&gt;nil map 是一种特殊的值，代表一个不存在的 map。它们拥有以下特性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;无法访问其中的元素，否则会导致 panic&lt;/li&gt;
&lt;li&gt;长度始终为 0&lt;/li&gt;
&lt;li&gt;可以删除元素，但没有任何实际意义&lt;/li&gt;
&lt;li&gt;不能向其中添加元素，否则会导致 panic&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;理解 nil map 的特性对于编写健壮可靠的 Go 程序至关重要。请务必牢记上述要点，避免在代码中出现 nil map 相关的错误。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：切片</title><link>https://blog.ithuo.net/posts/go-language-slice-tutoria/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-language-slice-tutoria/</guid><pubDate>Wed, 04 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在这篇教程中，我们将详细解释一段Go语言代码，帮助你理解切片的容量（capacity）和长度（length）是如何变化的。我们将通过三个示例来展示这些概念。&lt;/p&gt;
&lt;h2&gt;示例1：动态扩展切片&lt;/h2&gt;
&lt;p&gt;首先，我们来看第一个示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import &quot;fmt&quot;

func main() {
    // 示例1。
    s6 := make([]int, 0)
    fmt.Printf(&quot;The capacity of s6: %d\\n&quot;, cap(s6))
    for i := 1; i &amp;lt;= 5; i++ {
        s6 = append(s6, i)
        fmt.Printf(&quot;s6(%d): len: %d, cap: %d\\n&quot;, i, len(s6), cap(s6))
    }
    fmt.Println()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;解释&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;s6 := make([]int, 0)&lt;/code&gt;：创建一个长度和容量都为0的空切片。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fmt.Printf(&quot;The capacity of s6: %d\\n&quot;, cap(s6))&lt;/code&gt;：打印初始容量，应该是0。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;for i := 1; i &amp;lt;= 5; i++&lt;/code&gt;：循环5次，每次向切片&lt;code&gt;append&lt;/code&gt;一个元素。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s6 = append(s6, i)&lt;/code&gt;：向切片&lt;code&gt;append&lt;/code&gt;元素&lt;code&gt;i&lt;/code&gt;，切片会自动扩展。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fmt.Printf(&quot;s6(%d): len: %d, cap: %d\\n&quot;, i, len(s6), cap(s6))&lt;/code&gt;：打印每次&lt;code&gt;append&lt;/code&gt;后的长度和容量。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;结果&lt;/h3&gt;
&lt;p&gt;每次&lt;code&gt;append&lt;/code&gt;操作都会导致切片的长度增加1，而容量会根据需要动态扩展。通常，容量会按一定的倍数增长，以减少频繁的内存分配。&lt;/p&gt;
&lt;h2&gt;示例2：预分配大容量切片&lt;/h2&gt;
&lt;p&gt;接下来是第二个示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import &quot;fmt&quot;

func main() {
    // 示例2。
    s7 := make([]int, 1024)
    fmt.Printf(&quot;The capacity of s7: %d\\n&quot;, cap(s7))
    s7e1 := append(s7, make([]int, 200)...)
    fmt.Printf(&quot;s7e1: len: %d, cap: %d\\n&quot;, len(s7e1), cap(s7e1))
    s7e2 := append(s7, make([]int, 400)...)
    fmt.Printf(&quot;s7e2: len: %d, cap: %d\\n&quot;, len(s7e2), cap(s7e2))
    s7e3 := append(s7, make([]int, 600)...)
    fmt.Printf(&quot;s7e3: len: %d, cap: %d\\n&quot;, len(s7e3), cap(s7e3))
    fmt.Println()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;解释&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;s7 := make([]int, 1024)&lt;/code&gt;：创建一个长度和容量都为1024的切片。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fmt.Printf(&quot;The capacity of s7: %d\\n&quot;, cap(s7))&lt;/code&gt;：打印初始容量，应该是1024。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s7e1 := append(s7, make([]int, 200)...)&lt;/code&gt;：向&lt;code&gt;s7&lt;/code&gt;追加200个元素，生成新的切片&lt;code&gt;s7e1&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fmt.Printf(&quot;s7e1: len: %d, cap: %d\\n&quot;, len(s7e1), cap(s7e1))&lt;/code&gt;：打印&lt;code&gt;s7e1&lt;/code&gt;的长度和容量。&lt;/li&gt;
&lt;li&gt;类似地，&lt;code&gt;s7e2&lt;/code&gt;和&lt;code&gt;s7e3&lt;/code&gt;分别追加400和600个元素，并打印它们的长度和容量。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;结果&lt;/h3&gt;
&lt;p&gt;由于&lt;code&gt;s7&lt;/code&gt;的初始容量较大，追加200个元素不会导致容量变化。但追加400和600个元素时，容量会根据需要扩展。&lt;/p&gt;
&lt;h2&gt;示例3：小容量切片的扩展&lt;/h2&gt;
&lt;p&gt;最后是第三个示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import &quot;fmt&quot;

func main() {
    // 示例3。
    s8 := make([]int, 10)
    fmt.Printf(&quot;The capacity of s8: %d\\n&quot;, cap(s8))
    s8a := append(s8, make([]int, 11)...)
    fmt.Printf(&quot;s8a: len: %d, cap: %d\\n&quot;, len(s8a), cap(s8a))
    s8b := append(s8a, make([]int, 23)...)
    fmt.Printf(&quot;s8b: len: %d, cap: %d\\n&quot;, len(s8b), cap(s8b))
    s8c := append(s8b, make([]int, 45)...)
    fmt.Printf(&quot;s8c: len: %d, cap: %d\\n&quot;, len(s8c), cap(s8c))
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;解释&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;s8 := make([]int, 10)&lt;/code&gt;：创建一个长度和容量都为10的切片。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fmt.Printf(&quot;The capacity of s8: %d\\n&quot;, cap(s8))&lt;/code&gt;：打印初始容量，应该是10。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s8a := append(s8, make([]int, 11)...)&lt;/code&gt;：向&lt;code&gt;s8&lt;/code&gt;追加11个元素，生成新的切片&lt;code&gt;s8a&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fmt.Printf(&quot;s8a: len: %d, cap: %d\\n&quot;, len(s8a), cap(s8a))&lt;/code&gt;：打印&lt;code&gt;s8a&lt;/code&gt;的长度和容量。&lt;/li&gt;
&lt;li&gt;类似地，&lt;code&gt;s8b&lt;/code&gt;和&lt;code&gt;s8c&lt;/code&gt;分别追加23和45个元素，并打印它们的长度和容量。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;结果&lt;/h3&gt;
&lt;p&gt;由于&lt;code&gt;s8&lt;/code&gt;的初始容量较小，追加11个元素会导致容量扩展。追加23和45个元素时，容量会进一步扩展。&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;通过这三个示例，我们可以看到：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;切片的容量会根据需要动态扩展，以减少频繁的内存分配。&lt;/li&gt;
&lt;li&gt;初始容量较大的切片在追加元素时，容量变化较小。&lt;/li&gt;
&lt;li&gt;初始容量较小的切片在追加大量元素时，容量会显著扩展。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;希望这个教程能帮助你更好地理解Go语言中切片的容量和长度变化。如果有任何问题，欢迎随时提问！&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：深入理解数据类型转换与字符串处理</title><link>https://blog.ithuo.net/posts/go-data-type-conversion-and-string-handling-tutorial/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-data-type-conversion-and-string-handling-tutorial/</guid><pubDate>Tue, 03 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在这篇教程中，我们将通过一个示例代码来详细解释Go语言中的数据类型转换和字符串处理。我们将重点关注以下几个方面：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;数据类型转换及其二进制表示&lt;/li&gt;
&lt;li&gt;特殊字符的处理&lt;/li&gt;
&lt;li&gt;字符串与字节、rune的相互转换&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;示例代码&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;fmt&quot;
)

func main() {
	// 重点1的示例。
	var srcInt = int16(-255)
	// 请注意，之所以要执行uint16(srcInt)，是因为只有这样才能得到全二进制的表示。
	// 例如，fmt.Printf(&quot;%b&quot;, srcInt)将打印出&quot;-11111111&quot;，后者是负数符号再加上srcInt的绝对值的补码。
	// 而fmt.Printf(&quot;%b&quot;, uint16(srcInt))才会打印出srcInt原值的补码&quot;1111111100000001&quot;。
	fmt.Printf(&quot;The complement of srcInt: %b (%b)\n&quot;,
		uint16(srcInt), srcInt)
	dstInt := int8(srcInt)
	fmt.Printf(&quot;The complement of dstInt: %b (%b)\n&quot;,
		uint8(dstInt), dstInt)
	fmt.Printf(&quot;The value of dstInt: %d\n&quot;, dstInt)
	fmt.Println()

	// 重点2的示例。
	fmt.Printf(&quot;The Replacement Character: %s\n&quot;, string(-1))
	fmt.Printf(&quot;The Unicode codepoint of Replacement Character: %U\n&quot;, &apos;�&apos;)
	fmt.Println()

	// 重点3的示例。
	srcStr := &quot;你好&quot;
	fmt.Printf(&quot;The string: %q\n&quot;, srcStr)
	fmt.Printf(&quot;The hex of %q: %x\n&quot;, srcStr, srcStr)
	fmt.Printf(&quot;The byte slice of %q: % x\n&quot;, srcStr, []byte(srcStr))
	fmt.Printf(&quot;The string: %q\n&quot;, string([]byte{&apos;\xe4&apos;, &apos;\xbd&apos;, &apos;\xa0&apos;, &apos;\xe5&apos;, &apos;\xa5&apos;, &apos;\xbd&apos;}))
	fmt.Printf(&quot;The rune slice of %q: %U\n&quot;, srcStr, []rune(srcStr))
	fmt.Printf(&quot;The string: %q\n&quot;, string([]rune{&apos;\u4F60&apos;, &apos;\u597D&apos;}))
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;重点1：数据类型转换及其二进制表示&lt;/h3&gt;
&lt;p&gt;在Go语言中，数据类型转换是一个常见的操作。以下是一个将&lt;code&gt;int16&lt;/code&gt;类型转换为&lt;code&gt;uint16&lt;/code&gt;类型的示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var srcInt = int16(-255)
fmt.Printf(&quot;The complement of srcInt: %b (%b)\n&quot;, uint16(srcInt), srcInt)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;srcInt&lt;/code&gt;被定义为&lt;code&gt;int16&lt;/code&gt;类型，值为-255。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fmt.Printf(&quot;%b&quot;, srcInt)&lt;/code&gt;将打印出&lt;code&gt;-11111111&lt;/code&gt;，这是负数符号加上&lt;code&gt;srcInt&lt;/code&gt;的绝对值的补码。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fmt.Printf(&quot;%b&quot;, uint16(srcInt))&lt;/code&gt;将打印出&lt;code&gt;srcInt&lt;/code&gt;的原值补码&lt;code&gt;1111111100000001&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;接下来，我们将&lt;code&gt;srcInt&lt;/code&gt;转换为&lt;code&gt;int8&lt;/code&gt;类型：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dstInt := int8(srcInt)
fmt.Printf(&quot;The complement of dstInt: %b (%b)\n&quot;, uint8(dstInt), dstInt)
fmt.Printf(&quot;The value of dstInt: %d\n&quot;, dstInt)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;dstInt&lt;/code&gt;被定义为&lt;code&gt;int8&lt;/code&gt;类型，值为&lt;code&gt;srcInt&lt;/code&gt;转换后的结果。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fmt.Printf(&quot;%b&quot;, uint8(dstInt))&lt;/code&gt;将打印出&lt;code&gt;dstInt&lt;/code&gt;的补码。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fmt.Printf(&quot;The value of dstInt: %d\n&quot;, dstInt)&lt;/code&gt;将打印出&lt;code&gt;dstInt&lt;/code&gt;的十进制值。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;重点2：特殊字符的处理&lt;/h3&gt;
&lt;p&gt;在Go语言中，处理特殊字符时需要注意其Unicode码点。例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fmt.Printf(&quot;The Replacement Character: %s\n&quot;, string(-1))
fmt.Printf(&quot;The Unicode codepoint of Replacement Character: %U\n&quot;, &apos;�&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;string(-1)&lt;/code&gt;将输出替换字符&lt;code&gt;�&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fmt.Printf(&quot;%U&quot;, &apos;�&apos;)&lt;/code&gt;将输出替换字符的Unicode码点&lt;code&gt;U+FFFD&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;重点3：字符串与字节、rune的相互转换&lt;/h3&gt;
&lt;p&gt;在Go语言中，字符串可以方便地转换为字节切片和rune切片。以下是一个示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;srcStr := &quot;你好&quot;
fmt.Printf(&quot;The string: %q\n&quot;, srcStr)
fmt.Printf(&quot;The hex of %q: %x\n&quot;, srcStr, srcStr)
fmt.Printf(&quot;The byte slice of %q: % x\n&quot;, srcStr, []byte(srcStr))
fmt.Printf(&quot;The string: %q\n&quot;, string([]byte{&apos;\xe4&apos;, &apos;\xbd&apos;, &apos;\xa0&apos;, &apos;\xe5&apos;, &apos;\xa5&apos;, &apos;\xbd&apos;}))
fmt.Printf(&quot;The rune slice of %q: %U\n&quot;, srcStr, []rune(srcStr))
fmt.Printf(&quot;The string: %q\n&quot;, string([]rune{&apos;\u4F60&apos;, &apos;\u597D&apos;}))
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;srcStr&lt;/code&gt;被定义为字符串&lt;code&gt;&quot;你好&quot;&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fmt.Printf(&quot;%x&quot;, srcStr)&lt;/code&gt;将输出字符串的十六进制表示。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fmt.Printf(&quot;% x&quot;, []byte(srcStr))&lt;/code&gt;将输出字符串的字节切片。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;string([]byte{&apos;\xe4&apos;, &apos;\xbd&apos;, &apos;\xa0&apos;, &apos;\xe5&apos;, &apos;\xa5&apos;, &apos;\xbd&apos;})&lt;/code&gt;将字节切片转换回字符串。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fmt.Printf(&quot;%U&quot;, []rune(srcStr))&lt;/code&gt;将输出字符串的rune切片。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;string([]rune{&apos;\u4F60&apos;, &apos;\u597D&apos;})&lt;/code&gt;将rune切片转换回字符串。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通过以上示例，我们可以更好地理解Go语言中的数据类型转换和字符串处理。希望这篇教程对你有所帮助！&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Go语言教程：理解和应用类型断言与类型转换</title><link>https://blog.ithuo.net/posts/go-understanding-and-applying-type-assertions-and-type-conversions/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-understanding-and-applying-type-assertions-and-type-conversions/</guid><pubDate>Mon, 02 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在本教程中，我们将通过一段Go代码帮助你理解类型断言和类型转换的应用模式。我们将逐步解析代码，并解释每个部分的功能和用途。&lt;/p&gt;
&lt;h2&gt;代码概述&lt;/h2&gt;
&lt;p&gt;这段代码展示了如何使用类型断言和类型转换来处理不同类型的容器（如切片和映射）。代码包含两个主要部分：在&lt;code&gt;main&lt;/code&gt;函数中直接进行类型断言，以及通过一个辅助函数&lt;code&gt;getElement&lt;/code&gt;来处理类型转换。&lt;/p&gt;
&lt;h2&gt;代码详解&lt;/h2&gt;
&lt;h3&gt;包和变量声明&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;fmt&quot;
)

var container = []string{&quot;zero&quot;, &quot;one&quot;, &quot;two&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;package main&lt;/code&gt;：声明这是一个可执行程序。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;import &quot;fmt&quot;&lt;/code&gt;：导入&lt;code&gt;fmt&lt;/code&gt;包，用于格式化输入输出。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;var container = []string{&quot;zero&quot;, &quot;one&quot;, &quot;two&quot;}&lt;/code&gt;：声明一个全局变量&lt;code&gt;container&lt;/code&gt;，类型为字符串切片。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;主函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func main() {
	container := map[int]string{0: &quot;zero&quot;, 1: &quot;one&quot;, 2: &quot;two&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;container := map[int]string{0: &quot;zero&quot;, 1: &quot;one&quot;, 2: &quot;two&quot;}&lt;/code&gt;：在&lt;code&gt;main&lt;/code&gt;函数中，声明一个局部变量&lt;code&gt;container&lt;/code&gt;，类型为映射（map），覆盖了全局变量&lt;code&gt;container&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;方式1：直接类型断言&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// 方式1。
	_, ok1 := interface{}(container).([]string)
	_, ok2 := interface{}(container).(map[int]string)
	if !(ok1 || ok2) {
		fmt.Printf(&quot;Error: unsupported container type: %T\\n&quot;, container)
		return
	}
	fmt.Printf(&quot;The element is %q. (container type: %T)\\n&quot;,
		container[1], container)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;interface{}(container).([]string)&lt;/code&gt;：将&lt;code&gt;container&lt;/code&gt;转换为&lt;code&gt;interface{}&lt;/code&gt;类型，然后尝试断言为&lt;code&gt;[]string&lt;/code&gt;类型。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;interface{}(container).(map[int]string)&lt;/code&gt;：将&lt;code&gt;container&lt;/code&gt;转换为&lt;code&gt;interface{}&lt;/code&gt;类型，然后尝试断言为&lt;code&gt;map[int]string&lt;/code&gt;类型。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;if !(ok1 || ok2)&lt;/code&gt;：检查&lt;code&gt;container&lt;/code&gt;是否为&lt;code&gt;[]string&lt;/code&gt;或&lt;code&gt;map[int]string&lt;/code&gt;类型。如果都不是，打印错误信息并返回。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fmt.Printf(&quot;The element is %q. (container type: %T)\\n&quot;, container, container)&lt;/code&gt;：打印&lt;code&gt;container&lt;/code&gt;的第一个元素和类型。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;方式2：通过辅助函数进行类型转换&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// 方式2。
	elem, err := getElement(container)
	if err != nil {
		fmt.Printf(&quot;Error: %s\\n&quot;, err)
		return
	}
	fmt.Printf(&quot;The element is %q. (container type: %T)\\n&quot;,
		elem, container)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;elem, err := getElement(container)&lt;/code&gt;：调用&lt;code&gt;getElement&lt;/code&gt;函数获取&lt;code&gt;container&lt;/code&gt;的第一个元素。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;if err != nil&lt;/code&gt;：检查是否有错误发生。如果有，打印错误信息并返回。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fmt.Printf(&quot;The element is %q. (container type: %T)\\n&quot;, elem, container)&lt;/code&gt;：打印元素和类型。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;辅助函数&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;func getElement(containerI interface{}) (elem string, err error) {
	switch t := containerI.(type) {
	case []string:
		elem = t[1]
	case map[int]string:
		elem = t[1]
	default:
		err = fmt.Errorf(&quot;unsupported container type: %T&quot;, containerI)
		return
	}
	return
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;func getElement(containerI interface{}) (elem string, err error)&lt;/code&gt;：定义一个函数，接受一个&lt;code&gt;interface{}&lt;/code&gt;类型的参数，返回一个字符串和一个错误。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;switch t := containerI.(type)&lt;/code&gt;：使用类型断言检查&lt;code&gt;containerI&lt;/code&gt;的具体类型。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;case []string&lt;/code&gt;：如果&lt;code&gt;containerI&lt;/code&gt;是&lt;code&gt;[]string&lt;/code&gt;类型，获取第一个元素。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;case map[int]string&lt;/code&gt;：如果&lt;code&gt;containerI&lt;/code&gt;是&lt;code&gt;map[int]string&lt;/code&gt;类型，获取第一个元素。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;default&lt;/code&gt;：如果&lt;code&gt;containerI&lt;/code&gt;不是上述两种类型，返回错误。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;这段代码展示了如何使用类型断言和类型转换来处理不同类型的容器。通过直接在&lt;code&gt;main&lt;/code&gt;函数中进行类型断言和使用辅助函数&lt;code&gt;getElement&lt;/code&gt;，我们可以灵活地处理不同类型的数据结构。这种方法在需要处理多种类型的情况下非常有用，可以提高代码的可读性和可维护性。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>玩转Go语言之-Flag</title><link>https://blog.ithuo.net/posts/go-language-from-zero-to-hero-tutorial-flag/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-language-from-zero-to-hero-tutorial-flag/</guid><pubDate>Sun, 01 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Go语言学习教程：命令行标志解析&lt;/h1&gt;
&lt;p&gt;在本节中，我们将详细讲解如何使用Go语言中的&lt;code&gt;flag&lt;/code&gt;包来解析命令行标志。我们将通过一个简单的示例代码来逐步解释每个部分的功能和用法。&lt;/p&gt;
&lt;h2&gt;示例代码&lt;/h2&gt;
&lt;p&gt;以下是我们将要讲解的示例代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;flag&quot;
	&quot;fmt&quot;
	&quot;os&quot;
)

var name string

func init() {
	flag.CommandLine = flag.NewFlagSet(&quot;&quot;, flag.ExitOnError)
	flag.CommandLine.Usage = func() {
		fmt.Fprintf(os.Stderr, &quot;Usage of %s:\\n&quot;, &quot;question&quot;)
		flag.PrintDefaults()
	}
	flag.StringVar(&amp;amp;name, &quot;name&quot;, &quot;everyone&quot;, &quot;The greeting object.&quot;)
}

func main() {
	flag.Parse()
	fmt.Printf(&quot;Hello, %s!\\n&quot;, name)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;代码详解&lt;/h2&gt;
&lt;h3&gt;包导入&lt;/h3&gt;
&lt;p&gt;首先，我们导入了三个包：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import (
	&quot;flag&quot;
	&quot;fmt&quot;
	&quot;os&quot;
)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;flag&lt;/code&gt;包用于解析命令行标志。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fmt&lt;/code&gt;包用于格式化输入和输出。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;os&lt;/code&gt;包提供了一些操作系统功能，如标准输入输出。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;全局变量&lt;/h3&gt;
&lt;p&gt;我们定义了一个全局变量&lt;code&gt;name&lt;/code&gt;，用于存储命令行标志的值：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var name string
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;init&lt;/code&gt;函数&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;init&lt;/code&gt;函数在&lt;code&gt;main&lt;/code&gt;函数之前自动执行，用于初始化命令行标志的设置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func init() {
	flag.CommandLine = flag.NewFlagSet(&quot;&quot;, flag.ExitOnError)
	flag.CommandLine.Usage = func() {
		fmt.Fprintf(os.Stderr, &quot;Usage of %s:\\n&quot;, &quot;question&quot;)
		flag.PrintDefaults()
	}
	flag.StringVar(&amp;amp;name, &quot;name&quot;, &quot;everyone&quot;, &quot;The greeting object.&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;flag.CommandLine = flag.NewFlagSet(&quot;&quot;, flag.ExitOnError)&lt;/code&gt;：创建一个新的命令行标志集，并设置在解析错误时退出程序。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;flag.CommandLine.Usage&lt;/code&gt;：自定义命令行标志的使用说明。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;flag.StringVar(&amp;amp;name, &quot;name&quot;, &quot;everyone&quot;, &quot;The greeting object.&quot;)&lt;/code&gt;：定义一个字符串类型的命令行标志&lt;code&gt;name&lt;/code&gt;，默认值为&lt;code&gt;&quot;everyone&quot;&lt;/code&gt;，描述为&lt;code&gt;&quot;The greeting object.&quot;&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;code&gt;main&lt;/code&gt;函数&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;main&lt;/code&gt;函数是程序的入口点：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func main() {
	flag.Parse()
	fmt.Printf(&quot;Hello, %s!\\n&quot;, name)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;flag.Parse()&lt;/code&gt;：解析命令行标志。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fmt.Printf(&quot;Hello, %s!\\n&quot;, name)&lt;/code&gt;：根据解析的标志值输出问候语。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;运行示例&lt;/h2&gt;
&lt;p&gt;假设我们将代码保存为&lt;code&gt;main.go&lt;/code&gt;，可以通过以下命令运行程序：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go run main.go -name=GoLang
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输出将会是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Hello, GoLang!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果不提供&lt;code&gt;-name&lt;/code&gt;标志，程序将使用默认值&lt;code&gt;&quot;everyone&quot;&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go run main.go
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输出将会是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Hello, everyone!
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;通过这个示例，我们学习了如何使用Go语言的&lt;code&gt;flag&lt;/code&gt;包来解析命令行标志。我们介绍了如何定义和解析标志，以及如何自定义使用说明。希望这个教程对你理解Go语言的命令行标志解析有所帮助。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>玩转Go语言之-首篇</title><link>https://blog.ithuo.net/posts/go-language-from-zero-to-hero-tutorial-zero/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/go-language-from-zero-to-hero-tutorial-zero/</guid><pubDate>Sun, 01 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Go语言学习教程&lt;/h1&gt;
&lt;h2&gt;1. 引言&lt;/h2&gt;
&lt;p&gt;Go语言（简称Go或Golang）是由Google开发的一种静态类型、编译型的编程语言。自2009年发布以来，Go语言因其简洁、高效和并发编程的强大支持，迅速在开发者社区中流行起来。本教程将通过代码示例和具体案例，通俗易懂地介绍Go语言的基础知识、发展史、与其他语言的对比、生态系统以及开发者社区。&lt;/p&gt;
&lt;h2&gt;2. Go语言的发展史&lt;/h2&gt;
&lt;p&gt;Go语言的开发始于2007年，由Robert Griesemer、Rob Pike和Ken Thompson三位计算机科学家在Google内部发起。2009年11月，Go语言正式对外发布。其设计目标是解决当时软件开发中存在的复杂性和效率问题，特别是在多核处理器和网络服务的背景下。&lt;/p&gt;
&lt;p&gt;Go语言的设计理念包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;简洁性&lt;/strong&gt;：减少不必要的复杂性，使代码更易读、易维护。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;高效性&lt;/strong&gt;：编译速度快，运行时性能高。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;并发性&lt;/strong&gt;：内置强大的并发编程支持，适合处理高并发任务。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3. Go语言与其他语言的对比&lt;/h2&gt;
&lt;h3&gt;3.1 与C/C++的对比&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;简洁性&lt;/strong&gt;：Go语言去掉了C/C++中的许多复杂特性，如头文件、宏定义、指针运算等，使代码更简洁。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内存管理&lt;/strong&gt;：Go语言内置垃圾回收机制，自动管理内存，减少了手动管理内存的负担。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;并发性&lt;/strong&gt;：Go语言内置goroutine和channel，提供了简单高效的并发编程模型，而C/C++需要依赖第三方库（如pthread）实现并发。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3.2 与Java的对比&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;编译速度&lt;/strong&gt;：Go语言的编译速度非常快，通常只需几秒钟，而Java的编译速度相对较慢。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;部署&lt;/strong&gt;：Go语言编译生成的二进制文件无需依赖运行时环境，部署简单，而Java需要依赖JVM。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;并发性&lt;/strong&gt;：Go语言的并发模型更轻量级，goroutine的开销远小于Java的线程。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3.3 与Python的对比&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;性能&lt;/strong&gt;：Go语言是编译型语言，运行速度比解释型的Python快得多。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;类型系统&lt;/strong&gt;：Go语言是静态类型语言，编译时进行类型检查，而Python是动态类型语言，运行时进行类型检查。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;并发性&lt;/strong&gt;：Go语言内置并发支持，而Python的GIL（全局解释器锁）限制了其并发性能。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4. Go语言的生态&lt;/h2&gt;
&lt;p&gt;Go语言的生态系统非常丰富，涵盖了从Web开发、云计算、网络编程到数据处理等各个领域。以下是一些重要的Go语言生态组件：&lt;/p&gt;
&lt;h3&gt;4.1 标准库&lt;/h3&gt;
&lt;p&gt;Go语言的标准库非常强大，提供了丰富的功能模块，如网络编程、文件操作、字符串处理、加密算法等。以下是一个使用标准库进行HTTP服务器开发的示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;fmt&quot;
	&quot;net/http&quot;
)

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, &quot;Hello, World!&quot;)
}

func main() {
	http.HandleFunc(&quot;/&quot;, handler)
	http.ListenAndServe(&quot;:8080&quot;, nil)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4.2 第三方库&lt;/h3&gt;
&lt;p&gt;Go语言的第三方库生态也非常活跃，以下是一些常用的第三方库：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Gin&lt;/strong&gt;：一个高性能的HTTP Web框架。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gorm&lt;/strong&gt;：一个ORM库，用于数据库操作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cobra&lt;/strong&gt;：一个用于创建命令行应用程序的库。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4.3 工具链&lt;/h3&gt;
&lt;p&gt;Go语言提供了一整套工具链，包括编译器、包管理工具、测试工具等。以下是一些常用的Go工具：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;go build&lt;/strong&gt;：编译Go程序。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;go test&lt;/strong&gt;：运行测试。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;go fmt&lt;/strong&gt;：格式化代码。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;go mod&lt;/strong&gt;：管理依赖。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;5. Go语言开发者社区&lt;/h2&gt;
&lt;p&gt;Go语言的开发者社区非常活跃，以下是一些重要的社区资源：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;官方文档&lt;/strong&gt;：Go语言的官方文档详细介绍了语言特性和标准库使用方法。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Go论坛&lt;/strong&gt;：一个讨论Go语言相关问题的社区。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub&lt;/strong&gt;：许多开源项目和库都托管在GitHub上，开发者可以在这里找到丰富的资源。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GopherCon&lt;/strong&gt;：每年一度的Go语言开发者大会，汇聚了全球的Go语言爱好者和专家。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;为什么应该学习Go语言&lt;/h2&gt;
&lt;h3&gt;1. 简洁易学&lt;/h3&gt;
&lt;p&gt;Go语言的语法简洁明了，学习曲线相对平缓。对于初学者来说，Go语言提供了一个友好的编程环境，使他们能够快速上手并编写高效的代码。&lt;/p&gt;
&lt;h3&gt;2. 高效性能&lt;/h3&gt;
&lt;p&gt;Go语言的性能接近C语言，而开发效率则接近PHP。它的静态编译特性和高效的垃圾回收机制使得Go语言在处理高并发和大规模数据处理方面表现出色。&lt;/p&gt;
&lt;h3&gt;3. 强大的并发处理能力&lt;/h3&gt;
&lt;p&gt;Go语言内置的goroutine和channel机制使得并发编程变得简单高效。开发者可以轻松编写高并发的应用程序，而不需要过多关注底层的并发细节。&lt;/p&gt;
&lt;h3&gt;4. 丰富的标准库&lt;/h3&gt;
&lt;p&gt;Go语言提供了丰富的标准库，涵盖了从网络编程、文件操作到加密算法等各个方面。开发者可以利用这些标准库快速构建功能强大的应用程序。&lt;/p&gt;
&lt;h3&gt;5. 活跃的开发者社区&lt;/h3&gt;
&lt;p&gt;Go语言拥有一个活跃的开发者社区，提供了丰富的学习资源和支持。无论是官方文档、社区论坛还是开源项目，开发者都可以找到大量的资源来帮助他们学习和使用Go语言。&lt;/p&gt;
&lt;h2&gt;结论&lt;/h2&gt;
&lt;p&gt;Go语言以其简洁、高效和强大的并发处理能力，成为现代编程语言中的一颗新星。无论是Web开发、分布式系统还是云计算，Go语言都表现出色。通过学习Go语言，开发者可以掌握一门强大的工具，提升自己的编程技能和职业竞争力。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Notion示例文章</title><link>https://blog.ithuo.net/posts/notion-example-article/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/notion-example-article/</guid><pubDate>Mon, 08 Nov 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Notion-Markdown&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://1874.notion.site/Notion-0658ee89cadf4d0e9b6adfbb1d953c70&quot;&gt;Notion示例文章源地址&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;行内样式&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;加粗&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;斜体&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;u&amp;gt;下划线&amp;lt;/u&amp;gt;&lt;/p&gt;
&lt;p&gt;删除线&lt;/p&gt;
&lt;p&gt;行内代码 &lt;code&gt;const a = 123&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;行内公式，在Vitepress会报错，不做演示&lt;/p&gt;
&lt;p&gt;红色的文字&lt;/p&gt;
&lt;p&gt;蓝色的文字背景&lt;/p&gt;
&lt;p&gt;绿色的块背景&lt;/p&gt;
&lt;h2&gt;Basic block（基本块）&lt;/h2&gt;
&lt;h2&gt;Notion示例文章的子页面&lt;/h2&gt;
&lt;p&gt;Notion示例文章的子页面&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;表格标题&lt;/th&gt;
&lt;th&gt;备注&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;测试1&lt;/td&gt;
&lt;td&gt;啊大大&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;测试2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;const a = 123&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;无序列表&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;有序列表：事物按规律变化，也有一种不可避免的性质．这种性质就叫做&lt;strong&gt;必然性&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;事物的必然性，是事物本身的性质（我们反对宿命论的是其认为这一切是受神明的支配，而不是反对事物发展中存在的不可避免的性质的事实）
&lt;ol&gt;
&lt;li&gt;第三级别列表&lt;/li&gt;
&lt;li&gt;第三级别列表&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;其决定于它自己本身发展的情况和周围的条件
&lt;ol&gt;
&lt;li&gt;第三级别列表
&lt;ol&gt;
&lt;li&gt;第三级别列表
&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;折叠块：点击展开【一级】&amp;lt;/summary&amp;gt;
&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;点击展开【二级】&amp;lt;/summary&amp;gt;
&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;点击展开【三级】&amp;lt;/summary&amp;gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;内容文本&lt;/p&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;引用块&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;p&gt;👏 标注文本：&lt;strong&gt;Elog 0.4.0-beta.7 发布了！&lt;/strong&gt;&lt;br /&gt;
开放式跨平台博客解决方案，随意组合写作平台和部署平台&lt;/p&gt;
&lt;p&gt;帮助导航👇&lt;br /&gt;
❓ &lt;a href=&quot;https://elog.1874.cool/notion/introduce&quot;&gt;Elog能干什么&lt;/a&gt;&lt;br /&gt;
🚀 &lt;a href=&quot;https://elog.1874.cool/notion/start&quot;&gt;快速开始&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Media（媒体）&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/10a91945736a3027f2854218fa71c659.JPG&quot; alt=&quot;cover.JPG&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://elog.1874.cool&quot;&gt;bookmark&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pwd=&apos;123456&apos;
print(f&quot;password={pwd!r}&quot;)

## output:
#password=&apos;123456&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;DataBase（数据库）&lt;/h2&gt;
&lt;p&gt;数据库&lt;/p&gt;
&lt;h2&gt;AI block&lt;/h2&gt;
&lt;p&gt;API不支持，会报错&lt;code&gt;Block type ai_block is not supported via the API.&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Advanced block（高级块）&lt;/h2&gt;
&lt;p&gt;$$
f\left(\left[\frac{1+{x, y}}{\left(\frac{x}{y}+\frac{y}{x}\right)(u+1)}+a\right]^{3 / 2}\right)\tag{行标}
$$&lt;/p&gt;
&lt;p&gt;Notion示例文章的同步块&lt;/p&gt;
&lt;h1&gt;折叠一级标题&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;## 折叠二级标题


    折叠内容
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;两列分栏（左）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[ ] 左侧书写&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;两列分栏（右）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[ ] 右侧书写&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;graph LR;
Mermaid思维导图--&amp;gt;思维导图
Mermaid思维导图--&amp;gt;研发
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;@Anonymous&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.notion.so/f478ef37c82a41f1b7a59c195b043831&quot;&gt;Untitled&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2023-04-26&lt;/p&gt;
&lt;p&gt;🚀🔥🐸&lt;/p&gt;
&lt;h2&gt;Embeds（嵌入）&lt;/h2&gt;
&lt;p&gt;嵌入网页&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://elog.1874.cool&quot;&gt;embed&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: American Sports Vocabulary for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-american-sports-vocabulary-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-american-sports-vocabulary-a1-beginners/</guid><pubDate>Tue, 20 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=27&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak. Before we start, remember to subscribe to the channel, click on the bell and follow us on Instagram.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家好，欢迎观看初级英语听力视频。你可以用这个视频练习英语听力和理解能力。在开始之前，点选、关注、评论，一键三连。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You ready? So today I&apos;m gonna talk about American sports. Many foreigners don&apos;t know much about American sports. That&apos;s why this is a good topic to discuss. I&apos;m gonna talk about three American sports, basketball, baseball, and football. These are the most popular sports in the US.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;准备好了吗？所以今天我要谈谈美国的体育。许多外国人对美国的体育了解不多。这就是为什么这是一个好的讨论话题。我将谈论三项美国运动，篮球、棒球和橄榄球。这些是美国最受欢迎的运动。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;First, let&apos;s talk about basketball. Actually, this sport is popular in some other countries, too. For example, it&apos;s popular in some European and Asian countries, but it&apos;s more popular in America. In the US, our professional basketball league is called the NBA. The NBA has 30 teams, 29 American teams and one Canadian team, the Toronto Raptors. You probably know some of the famous NBA teams, like the Los Angeles Lakers and the Golden State Warriors. When I was younger, I was a big Lakers fan. I started watching their games when I was 6 years old. My favorite players were Shaq and Kobe. You might know those names.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;首先，让我们谈谈篮球。实际上，这项运动在其他国家也很受欢迎。例如，在一些欧洲和亚洲国家很流行，但在美国更受欢迎。在美国，我们的职业篮球联赛被称为NBA。NBA有30支球队，29支美国队和一支加拿大队，多伦多猛龙队。你可能知道一些著名的NBA球队，比如洛杉矶湖人队和金州勇士队。当我年轻的时候，我是湖人队的忠实粉丝。我六岁开始看他们的比赛。我最喜欢的球员是沙奎尔和科比。你可能知道这些名字。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So the rules of basketball are pretty simple. You try to shoot the ball into the hoop and you defend your hoop. If you score from close, it&apos;s two points. If you score from far away, it&apos;s three points. And if you score a foul shot or free throw, it&apos;s one point. The team who scores more points wins. Easy, right?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;所以篮球的规则相当简单。你尝试将球投进篮筐，同时防守你的篮筐。如果你近距离得分，那是两分。如果你远距离得分，那是三分。如果你得分是罚球或罚篮，那是一分。得分多的队获胜。简单，对吧？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;When I was a kid, I played basketball a lot. I was tall, so this really helped me. If you&apos;re tall, you have an advantage. Nowadays, I don&apos;t play basketball anymore.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;小时候，我经常打篮球。我很高，这对我帮助很大。如果你高，你就有优势。现在，我不再打篮球了。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, now let&apos;s talk about baseball. In the past, baseball was the most popular sport in America. But today, more Americans watch football. In the U.S., our professional baseball league is called the MLB. The MLB has 30 teams, just like the NBA.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，现在让我们来谈谈棒球。在过去，棒球是美国最受欢迎的运动。但今天，更多的美国人观看橄榄球。在美国，我们的职业棒球联盟被称为MLB。MLB有30支球队，就像NBA一样。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Baseball is popular in some countries outside the US. For example, people in the Caribbean love baseball, and it&apos;s also popular in some Asian countries. How about you? Do you like baseball?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;棒球在美国以外的一些国家也很受欢迎。例如，加勒比海地区的人们热爱棒球，在一些亚洲国家也很流行。你呢？你喜欢棒球吗？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So, the rules of baseball are complicated. There&apos;s no time in baseball. We don&apos;t have two halves or four quarters. Instead, there are nine innings. In each inning, both teams have the chance to play on offense and defense. I won&apos;t try to explain all the positions, but I will talk about the pitcher and batter. The pitcher is the person who throws the ball, and the batter is the person who hits the ball. The batter tries to hit the ball hard and far. The pitcher doesn&apos;t want the batter to hit the ball. There are many more rules and they&apos;re very complicated. But if you watch a few baseball games, you&apos;ll start to understand.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;那么，棒球的规则很复杂。棒球里没有时间限制。我们没有上下两个半场或四个小节。相反，有九个回合。在每个回合中，两个队伍都有机会进行进攻和防守。我不会尝试解释所有的位置，但我会谈谈投手和击球手。投手是投球的人，而击球手是击球的人。击球手试图用力和远地击球。投手不希望击球手击中球。还有更多的规则，它们非常复杂。但如果你观看几场棒球比赛，你就会开始理解。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I&apos;m not good at baseball, but I like going to baseball games. It&apos;s really fun to watch a baseball game in a baseball stadium.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我不擅长棒球，但我喜欢去看棒球比赛。在棒球场观看棒球比赛真的很有意思。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, lastly, let&apos;s talk about football. Remember that in the US, football is not soccer. When we say football, we&apos;re talking about American football. Today, football is the most popular sport in America. More people watch football than any other sport. Nowadays, It&apos;s becoming popular in other countries, too. Is American football popular in your country? So the rules of football are really complicated, and the rules change often.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，最后，让我们谈谈足球。记住，在美国，足球不是足球。当我们说足球时，我们指的是美式足球。今天，足球是美国最受欢迎的运动。观看足球比赛的人数超过了其他任何运动。现在，它在其他国家也越来越受欢迎了。美式足球在你们国家受欢迎吗？所以足球的规则非常复杂，而且规则经常变化。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you don&apos;t know the rules of football, it can be hard to understand what&apos;s happening when you watch a game. However, the objective of the game is simple. You wanna score more points than the other team. You can score touchdowns, which are six points. You can score field goals, which are three points, and you can score extra points, which are one point. One team is on offense and one team is on defense. The most important player is the quarterback. He&apos;s the player who throws the ball. And of course, the championship game is called the Super Bowl. This is a very popular event every year.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，最后，让我们谈谈足球。记住，在美国，足球不是足球。当我们说足球时，我们指的是美式足球。今天，足球是美国最受欢迎的运动。观看足球比赛的人数超过了其他任何运动。现在，它在其他国家也越来越受欢迎了。美式足球在你们国家受欢迎吗？所以足球的规则非常复杂，而且规则经常变化。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, now I&apos;m gonna ask you some questions about the video to see if you understood. Write your answers in a comment down below.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，现在我要问你一些关于视频的问题，看看你是否理解了。把你的答案写在下面的评论中。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;No.1, how many Canadian teams are in the NBA? No. 2, in baseball, what does the batter do? No. 3, in football, who is the most important player?&lt;/p&gt;
&lt;p&gt;Alright, remember to subscribe to the channel, click on the bell and follow us on Instagram for more English tips and lessons. I&apos;ll see you next time.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Money and Finance Vocabulary for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-money-finance-vocabulary-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-money-finance-vocabulary-a1-beginners/</guid><pubDate>Mon, 19 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=26&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey, everybody! Welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak. Before we start, remember to subscribe to the channel, click on the bell, and follow us on Instagram.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家好，欢迎观看初级英语听力视频。你可以用这个视频练习英语听力和理解能力。在开始之前，点选、关注、评论，一键三连。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You ready? So today, I&apos;m gonna talk about money. This is a really important topic because money is a big part of our lives.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;准备好了吗？那么今天，我要谈谈金钱。这是一个非常重要的话题，因为金钱是我们生活中很大一部分。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So first, let&apos;s talk about currencies. A currency is the type of money that a country uses. For example, the currency of the US is the dollar. And the currency of Mexico is the peso. Every country uses a currency to buy and sell things. Some currencies are very valuable, and other currencies are not very valuable. For example, today, one US dollar is worth 22 Mexican pesos. The dollar is more valuable right now. So, what currency does your country use?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;首先，我们来谈谈货币。货币是一个国家使用的钱的类型。例如，美国的货币是美元。墨西哥的货币是比索。每个国家都使用货币来买卖东西。有些货币非常有价值，而其他货币则不太有价值。例如，今天，一美元相当于22墨西哥比索。美元现在更有价值。那么，你们国家使用的是什么货币呢？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, now let&apos;s talk about prices. In the US, most things are expensive. They cost a lot of money. In other countries, things are cheap. They don&apos;t cost a lot of money. For instance, in the US, the average price of a house is about $250,000. But in Mexico, the average price of a house is probably around $40,000. That&apos;s a big difference. Prices are very different in different countries. Another major difference is with salaries. The salaries in some countries are high, and the salaries in other countries are low. In the US, salaries are pretty high. Americans need to make a lot of money because life is expensive in the US. In some countries, people don&apos;t need a lot of money to live, but everyone needs some money to survive.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;现在我们来谈谈价格。在美国，大多数东西都很贵。它们需要很多钱。在其他国家，东西便宜。它们不需要很多钱。例如，在美国，一套房子的平均价格大约是25万美元。但在墨西哥，一套房子的平均价格可能大约是4万美元。这是一个很大的差异。不同国家的价格差异非常大。另一个主要差异是工资。一些国家的工资很高，而其他国家的工资很低。在美国，工资相当高。美国人需要赚很多钱，因为在美国生活成本很高。在一些国家，人们不需要很多钱就能生活，但每个人都需要一些钱来生存。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, now let&apos;s talk about spending and saving money. Some people really like spending money, and other people prefer saving more money. Different people have different habits. My family always liked saving money. My mom taught me to always save some of my money. So today, I try to save some of the money I earn. It&apos;s not always easy to save, though. You have to be careful with your money because it&apos;s easy to spend too much.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，现在让我们来谈谈花钱和存钱。有些人真的很喜欢花钱，而另一些人则更倾向于存更多的钱。不同的人有不同的习惯。我的家人总是喜欢存钱。我妈妈教我一定要存一部分钱。所以今天，我尽量存下我赚的一些钱。不过，存钱并不总是容易的。你必须小心你的钱，因为很容易就会花得太多。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I know many people who don&apos;t save money. They always spend their money on clothes, electronics, vacations, and other things. I spend money on these things too, but not all my money. Some people spend all their money because they want to enjoy the moment. I don&apos;t think I could do this. I think it&apos;s good to enjoy the moment, but it&apos;s also good to plan for the future.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我知道很多人不存钱。他们总是把钱花在衣服、电子产品、度假和其他东西上。我也在这些东西上花钱，但不是我所有的钱。有些人把所有的钱都花光，因为他们想要享受当下。我不认为我能做到这样。我认为享受当下是好的，但为未来做计划也是好的。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One other thing that people do with their money is invest. You can invest in many different things like the stock market, real estate, currencies, or gold. Many Americans invest their money. They want to use this money to make more money in the future. In some countries, investing is not very popular, or sometimes they don&apos;t have good investment options. You need to be careful when you invest your money because not all investment options are good. Some investments are bad, and you can lose money. Overall, people have many different ways to manage their money.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;人们用钱做的另一件事是投资。你可以投资许多不同的东西，比如股票市场、房地产、货币或黄金。许多美国人会投资他们的钱。他们希望用这笔钱在未来赚更多的钱。在一些国家，投资并不十分流行，或者有时他们没有好的投资选择。你需要小心投资你的钱，因为并非所有投资选择都是好的。有些投资是坏的，你会赔钱。总的来说，人们有多种不同的方式来管理他们的钱。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;All right, that&apos;s all for today. Leave a comment and tell me if you like spending, saving, or investing money. And remember to subscribe to the channel, click on the bell, and follow us on Instagram for more English tips and lessons. I&apos;ll see you next time.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Education System and Vocabulary for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-education-system-vocabulary-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-education-system-vocabulary-a1-beginners/</guid><pubDate>Sun, 18 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=25&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak. Before we start, remember to subscribe to the channel, click on the bell, and follow us on Instagram. You ready?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家好，欢迎观看初级英语听力视频。你可以用这个视频练习英语听力和理解能力。在开始之前，点选、关注、评论，一键三连。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So today I&apos;m gonna talk about education. This is an essential topic because education is an important part of our lives. Most people get some kind of education. Education is different in different countries. But today we&apos;ll talk about education in the US.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;今天我要谈论教育。这是一个重要的主题，因为教育是我们生活中重要的一部分。大多数人会接受某种形式的教育。不同国家的教育各不相同。但今天我们要谈论美国的教育。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So first, let&apos;s talk about the different levels of education in the US.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;那么首先，让我们来谈谈美国不同的教育水平。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The first level of education is preschool. In the US, kids go to preschool when they&apos;re 4 years old. But not everyone goes to preschool. Some people don&apos;t go. I went to preschool when I was 4. I didn&apos;t like it because I was very shy. I didn&apos;t like playing with other kids when I was young. In preschool, children play a lot, but they also learn. After preschool, children go to kindergarten. Usually kids start kindergarten when they&apos;re 5 years old. In kindergarten, children start learning more things. For example, they learn to read, write and make art. They also learn how to be good students. I remember that when I was in kindergarten, we had discipline. If we did something bad, we got in trouble. I never got in trouble because I was a good student.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;教育的第一级是学前教育。在美国，孩子们四岁时去上幼儿园。但不是每个人都上幼儿园。有些人不去。我四岁的时候去了幼儿园。我不喜欢它，因为我当时非常害羞。我小时候不喜欢和其他孩子玩。在幼儿园，孩子们玩很多，但他们也学习。幼儿园之后，孩子们去上小学。通常孩子们五岁时开始上小学。在小学，孩子们开始学习更多的东西。例如，他们学习阅读、写作和制作艺术。他们还学习如何成为好学生。我记得当我在小学时，我们有纪律。如果我们做了坏事，我们就会陷入麻烦。我从未陷入麻烦，因为我是一个好学生。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So after kindergarten, you go to elementary school. In the US, most elementary schools include 1st, 2nd, 3rd, 4th, 5th, and 6th grade. But some elementary schools don&apos;t include 6th grade. In each year of elementary school, you only have one teacher. You have the same teacher all year. In my opinion, elementary school isn&apos;t that difficult in the US. Of course, you get homework, but it&apos;s not too much. In elementary school, you learn many things like math, science, history, and English. At this level, you spend about six hours at school.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;所以上完幼儿园后，你就去上小学。在美国，大多数小学包括一到六年级。但有些小学不包括六年级。在小学的每个学年，你只有一个老师。你全年都有同一个老师。在我看来，美国的小学并不太困难。当然，你会有家庭作业，但并不是太多。在小学，你会学到很多知识，比如数学、科学、历史和英语。在这个学习阶段，你每天在学校大约待六个小时。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Then after elementary school, you go to middle school or junior high. I say middle school, but both of these names are correct. Middle school usually includes 7th and 8th grade. At this level, students have many teachers, like 6 or 7. I had six different classes each year in middle school. Each class was one hour long. I didn&apos;t like middle school. It&apos;s much harder than elementary school. You get more homework and you have more tests. Then after middle school, you go to high school.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;然后小学毕业后，你会去上中学或者初中。我说中学，但这两个名称都是正确的。中学通常包括七年级和八年级。在这个学习阶段，学生有很多老师，比如6个或7个。我在中学每年有六门不同的课。每节课都是一小时长。我不喜欢中学。它比小学难多了。你会有更多的作业，还有更多的考试。然后中学毕业后，你会去上高中。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In the US, high school includes 9th, 10th, 11th, and 12th grade. This is the most important time for students in the US. If you wanna go to college, then it&apos;s important to do well in high school. High school can be difficult, but it depends on your teachers. Some teachers give a lot of homework and some teachers don&apos;t. And some teachers are good at teaching and some teachers aren&apos;t. I had some good teachers in high school, but I also had some bad teachers. So after high school, some people go to college and some people don&apos;t. Of course, there are different levels of university and you can earn different degrees there.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;在美国，高中包括9年级、10年级、11年级和12年级。这是美国学生最重要的时期。如果你想上大学，那么在高中表现好就很重要。高中可能会很困难，但这取决于你的老师。有些老师布置很多作业，有些老师则不然。有些老师擅长教学，有些则不擅长。我在高中时遇到了一些好老师，但也遇到了一些不好的老师。所以高中毕业后，有些人会去上大学，有些人则不会。当然，大学有不同的层次，你可以在那里获得不同的学位。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, so lastly, let&apos;s look at a few important vocabulary words related to education. First, let&apos;s talk about the word grades. We use the word grades to talk about how well you did in a class or on a test. In the US, these grades are A, B, C, D, and F. And an A grade is the best and an F grade is the worst.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，最后，让我们来看一些与教育相关的重要的词汇。首先，让我们谈谈“成绩”这个词。我们用“成绩”这个词来谈论你在一门课程或一次考试中的表现如何。在美国，这些成绩是A、B、C、D和F。A等级是最好的，F等级是最差的。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, the next word is recess. In the US, recess is the short break that elementary school students have during their school day. During recess, students play, talk, or eat a snack. This break is usually 20 or 30 minutes.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，下一个词是“课间休息”。在美国，课间休息是小学生在一天的学校生活中所享有的短暂休息时间。在课间休息时，学生们玩耍、交谈或吃点心。这个休息时间通常是20或30分钟。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, the last phrase you should learn is bachelor&apos;s degree. A bachelor&apos;s degree is the degree you get after 4 years of university. It&apos;s lower than a master&apos;s degree.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，你最后应该学习的一个短语是“学士学位”。学士学位是你在大学学习四年后获得的学位。它低于硕士学位。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Alright, that&apos;s all for today. Leave a comment and tell me about your education. And remember to subscribe to the channel, click on the bell, and follow us on Instagram for more English tips and lessons. I&apos;ll see you next time.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Productivity Tips and Vocabulary for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-productivity-tips-vocabulary-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-productivity-tips-vocabulary-a1-beginners/</guid><pubDate>Sat, 17 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=24&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak. And remember to sign up for our $1 Listening Practice seminars at polyglossa.com to improve your listening fast.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家好，欢迎观看初级英语听力视频。你可以用这个视频练习英语听力和理解能力。记得点赞、关注、评论一键三连。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So today I&apos;m gonna talk about productivity. This is a great topic to talk about, because everybody wants to be productive. What does productivity mean? If you&apos;re productive, it means you produce a lot. It means that you see good results from your effort or work.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;今天我要聊聊生产力。这是一个很棒的话题，因为每个人都想要高效。生产力意味着什么？如果你有生产力，意味着你产出很多。它意味着你从你的努力或工作中看到了良好的结果。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So let&apos;s talk about some ways we can be productive.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;那么，让我们谈谈一些我们可以提高生产力的方法。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The first way we can be productive is by waking up early. I know that many of you don&apos;t like this advice. Not many people like waking up early. I wake up pretty early, but it&apos;s not easy for me. I usually wake up at 6 am Every day. This is early, but some people wake up earlier than me, like at 5:00am. I wake up early so I can be more productive every day. My official work starts at 7:30am. But since I wake up at 6, I can do more things before I start working. For example, I read a little bit in the morning and I study languages. I usually read for about 15 minutes and I can study languages for about 50 minutes. If I don&apos;t do this in the morning, I might not have time to do it later. So, I do all this before my work starts. I&apos;m pretty productive in the morning. How about you? Are you productive in the morning?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我们提高效率的第一种方式是早起。我知道你们中的许多人不喜欢这个建议。没有多少人喜欢早起。我起床相当早，但对我来说并不容易。我通常每天早上6点起床。这已经很早了，但有些人比我起得更早，比如在早上5点。我早起是为了让我每天都能更有效率。我的正式工作从早上7点半开始。但由于我6点就起床了，所以在我开始工作之前，我可以完成更多的事情。例如，早上我会读一会儿书，学习语言。我通常会读大约15分钟，我可以学习语言大约50分钟。如果我早上不这样做，我可能稍后就没有时间做了。所以，我会在工作开始之前完成所有这些。我早上效率很高。你呢？你早上效率如何？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, another way we can be productive is by removing distractions. A distraction is something that doesn&apos;t let you focus on your work. For example, if you&apos;re trying to work and you hear dogs barking outside, that might make you lose focus. Some distractions are hard to remove, like your neighbor&apos;s dog, but other distractions are easy to remove. For instance, you can silence your cell phone. If you hear your phone vibrate or ring, you usually wanna look at your phone. When my phone vibrates, I sometimes get distracted. If you want to remove this distraction, you can put your phone on silent or on airplane mode. For some people, this is hard. Some people don&apos;t wanna ignore their phone calls and messages. They think that it&apos;s very important to check their phone. This might be true, but it&apos;s also important to finish your work. If you silence your phone, it can help you finish your work faster. So removing distractions like this can be very helpful.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我们可以通过消除干扰来提高生产力。干扰是指那些让你无法专注于工作的事物。例如，如果你正在工作，听到外面狗叫，那可能会让你分心。有些干扰很难消除，比如邻居的狗，但其他干扰很容易消除。例如，你可以将手机调成静音。如果你听到手机震动或铃声，你通常会想要查看手机。当我的手机震动时，我有时会分心。如果你想消除这种干扰，你可以将手机调成静音或开启飞行模式。对某些人来说，这很难。有些人不想忽略他们的电话和消息。他们认为检查手机非常重要。这可能是真的，但完成你的工作也很重要。如果你将手机静音，它可以帮助您更快地完成工作。因此，消除这样的干扰可以非常有帮助。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, another way we can be more productive is by making sure that we&apos;re comfortable when we work. For example, if you&apos;re in an uncomfortable chair, or if you feel hot or cold, you might be less productive when you&apos;re working. In my case, I don&apos;t work well if my chair is uncomfortable. Usually my back hurts and I wanna change positions. So I need to sit in a comfortable chair when I work. Sometimes I sit on my couch when I work, because it&apos;s comfortable there. This helps me be more productive.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，我们可以通过消除干扰来提高生产力。干扰是指那些让你无法专注于工作的事物。例如，如果你正在工作，听到外面狗叫，那可能会让你分心。有些干扰很难消除，比如邻居的狗，但其他干扰很容易消除。例如，你可以将手机调成静音。如果你听到手机震动或铃声，你通常会想要查看手机。当我的手机震动时，我有时会分心。如果你想消除这种干扰，你可以将手机调成静音或开启飞行模式。对某些人来说，这很难。有些人不想忽略他们的电话和消息。他们认为检查手机非常重要。这可能是真的，但完成你的工作也很重要。如果你将手机静音，它可以帮助您更快地完成工作。因此，消除这样的干扰可以非常有帮助。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;All right. One more way that we can be productive is by setting goals. In my opinion, this is the best way to be productive. If you set goals for yourself, you feel motivated to work, you wanna achieve your goals. I always set goals for myself to help me be productive. It&apos;s good to set short term and long term goals. A short term goal is a goal you wanna achieve soon. A long term goal is a goal you wanna achieve after a long time. You can set short term and long term goals to help you learn English. For example, maybe your short term goal is to watch all my A1 listening practice videos by next month. And maybe your long term goal can be to read a whole book in English by the end of the year.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我们可以通过设定目标来提高生产力。在我看来，这是提高生产力的最好方法。如果你为自己设定了目标，你就会感到有动力去工作，你想要实现你的目标。我总是为自己设定目标来帮助我提高生产力。设定短期和长期目标都是很好的。短期目标是你想要很快实现的目标。长期目标是你想要在很长时间后实现的目标。你可以设定短期和长期目标来帮助你学习英语。例如，也许你的短期目标是在下个月之前观看完我所有的A1听力练习视频。也许你的长期目标是在年底之前读完一整本英文书。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You can set many types of goals for yourself. I like to set daily goals too. This helps me be productive every day. For instance, each day my goal is to practice my listening in French for one hour. Every day, when I complete this hour, I feel great. I know that I accomplished my goal. Okay, I hope you can use these tips to help you be more productive.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;你可以为自己设定多种类型的目标。我也喜欢设定每日目标。这有助于我每天都保持高效。例如，我每天的目标是练习法语听力一小时。每天，当我完成这一小时时，我感到很棒。我知道我完成了我的目标。好吧，我希望你们可以使用这些建议来帮助你们提高效率。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now I&apos;m gonna ask you some questions about the video to see if you understood. Write your answers in a comment down below.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;现在我要问你一些关于视频的问题，看看你是否理解了。把你的答案写在下面的评论中。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;No. 1, what&apos;s one activity I do before I start my work in the morning?&lt;/p&gt;
&lt;p&gt;No. 2, what&apos;s one thing that can distract us from our work?&lt;/p&gt;
&lt;p&gt;No. 3, what are two types of goals that we can set?&lt;/p&gt;
&lt;p&gt;All right, remember to sign up for our $1 listening practice seminars if you need more listening practice. And remember to subscribe to the channel, click on the bell and follow us on Instagram. I&apos;ll see you next time.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Soccer Vocabulary and Concepts for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-soccer-vocabulary-concepts-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-soccer-vocabulary-concepts-a1-beginners/</guid><pubDate>Fri, 16 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=23&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak. Before we start, remember to subscribe to the channel, click on the bell, and follow us on Instagram.&lt;/p&gt;
&lt;p&gt;大家好，欢迎观看初级英语听力视频，你可以用这个视频练习英语听力和理解能力。在开始之前，记得点赞、关注、评论一键三连。&lt;/p&gt;
&lt;p&gt;You ready? So today I&apos;m gonna talk about soccer. This is a really popular topic because many people love soccer. Soccer is the most popular sport in the world. It&apos;s the most important sport in the world.&lt;/p&gt;
&lt;p&gt;准备好了吗？所以今天我要聊聊足球。这是一个非常热门的话题，因为很多人都喜欢足球。足球是世界上最受欢迎的运动。它是世界上最重要的运动。&lt;/p&gt;
&lt;p&gt;Let&apos;s talk first about the rules of soccer. The objective of the game is to score more goals than the other team. If your team scores more goals than the other team, your team wins and the other team loses. But it&apos;s not easy to score goals. It&apos;s hard. Each team has defenders who try to stop you from scoring goals. Midfielders are the players that play in the middle of the field. They have to run a lot. I never liked being a midfielder, because I can&apos;t run a lot. The players that usually score goals are called forwards. Being a forward is fun because scoring goals is fun. Also, each team has a goalkeeper. The goalkeeper can use his hands and his whole body to defend the goal. In total, each team has 11 players on the field.&lt;/p&gt;
&lt;p&gt;我们首先来聊聊足球的规则。比赛的目的是比对方球队进更多的球。如果你的球队比对方球队进更多的球，你的球队就赢了，对方球队就输了。但是进球并不容易。这很难。每个球队都有防守队员，他们试图阻止你进球。中场球员是那些在场地中间踢球的球员。他们必须跑很多。我从来不喜欢当中场球员，因为我不能跑很多。通常进球的球员被称为前锋。当前锋很有趣，因为进球很有趣。此外，每个球队都有一个守门员。守门员可以用他的手和整个身体来防守球门。总共，每个球队在场上有11名球员。&lt;/p&gt;
&lt;p&gt;Now let&apos;s talk about soccer&apos;s popularity. In most countries, soccer is the biggest sport. Most cities have a local soccer team, and the people support their city&apos;s team. There are also national teams every four years, national teams compete for the World Cup. During this time, everyone supports their country&apos;s team. Some nations are very good, like Germany, France, and Brazil. Other nations are not so good. The US doesn&apos;t have a very good team because soccer is not very popular in the US; most Americans prefer other sports like American football, basketball, and baseball. Many children play soccer in the US, but not many people enjoy watching soccer. I played soccer when I was a child and it was fun for me. I liked being a forward because I wanted to score goals. I don&apos;t play soccer now though.&lt;/p&gt;
&lt;p&gt;现在让我们来聊聊足球的普及。在大多数国家，足球是最大的运动。大多数城市都有一支当地的足球队，人们支持他们城市的球队。每四年，每个国家的队伍还会组成国家队，国家队会为世界杯而竞争。在这段时间里，每个人都会支持他们国家的球队。有些国家非常出色，比如德国、法国和巴西。其他国家则不那么出色。美国并没有一个非常出色的球队，因为足球在美国并不十分流行；大多数美国人更喜欢其他运动，比如美式足球、篮球和棒球。在美国，许多孩子踢足球，但并没有很多人喜欢看足球比赛。当我还是个孩子的时候，我踢过足球，我觉得很有趣。我喜欢担任前锋，因为我想进球。不过，我现在不踢足球了。&lt;/p&gt;
&lt;p&gt;Okay, lastly, let&apos;s talk about soccer leagues around the world. Most countries have a domestic soccer league with local teams. Some famous soccer leagues include the English Premier League, La Liga in Spain, Bundesliga in Germany, and Serie A in Italy. These leagues have some very good teams; some of the best teams in the world include Real Madrid, Barcelona, Liverpool, Bayern Munich, and Juventus.&lt;/p&gt;
&lt;p&gt;好的，最后，让我们聊聊世界各地的足球联赛。大多数国家都有本国的足球联赛和当地球队。一些著名的足球联赛包括英格兰足球超级联赛、西班牙的西甲联赛、德国的德甲联赛和意大利的意甲联赛。这些联赛中有一些非常优秀的球队；世界上最好的球队包括皇家马德里、巴塞罗那、利物浦、拜仁慕尼黑和尤文图斯。&lt;/p&gt;
&lt;p&gt;In the past, I really liked watching Cristiano Ronaldo play. I watched him play for Real Madrid, Juventus, and Portugal. My favorite matches are the Champions League matches. The Champions League is the highest competition for European teams. Every year in the Champions League, the best teams in the world play against each other. It&apos;s always really exciting.&lt;/p&gt;
&lt;p&gt;过去，我非常喜欢看克里斯蒂亚诺·罗纳尔多踢球。我看过他在皇家马德里、尤文图斯和葡萄牙队的比赛。我最喜欢的比赛是欧洲冠军联赛的比赛。欧洲冠军联赛是欧洲球队的最高比赛。每年的欧洲冠军联赛，世界上最好的球队都会相互对抗。这总是非常激动人心的。&lt;/p&gt;
&lt;p&gt;Nowadays, I&apos;m not really interested in sports anymore, but once in a while I like watching soccer.&lt;/p&gt;
&lt;p&gt;如今，我对体育不再那么感兴趣了，但偶尔我还是喜欢观看足球比赛。&lt;/p&gt;
&lt;p&gt;Alright, that&apos;s all for today. Leave a comment and tell me who your favorite soccer team is. And remember to subscribe to the channel, click on the bell, and follow us on Instagram for more English tips and lessons. I&apos;ll see you next time.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Internet Vocabulary and Concepts for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-internet-vocabulary-concepts-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-internet-vocabulary-concepts-a1-beginners/</guid><pubDate>Thu, 15 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=22&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak. Before we start, remember to subscribe to the channel, click on the bell, and follow us on Instagram. You ready?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家好，欢迎观看初级英语听力视频。你可以用这个视频练习英语听力和理解能力。在开始之前，让我点赞、关注、评论一键三连。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So today, I&apos;m gonna talk about the internet. This is a very relevant topic, because all of us use the internet. If you&apos;re watching this video, that means you&apos;re using the internet. The internet is a really important invention. Can you imagine your life without it? I can&apos;t. So let&apos;s talk about the history, the use, the positives, and the negatives of the internet.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;那么今天，我要谈谈互联网。这是一个非常相关的话题，因为我们所有人都在使用互联网。如果你正在观看这个视频，那意味着你正在使用互联网。互联网是一个非常重要的发明。你能想象没有它的生活吗？我不能。那么让我们来谈谈互联网的历史、用途、优点和缺点。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The first version of the internet was created in the 1960s. This was a prototype. A prototype is an early model of a product. So, the prototype of the internet was the early version of the internet. It was created in the US, The U.S. government started this project. But that internet wasn&apos;t the same as today&apos;s internet. The world wide web was created in 1989. People didn&apos;t have the internet at home until later. For example, my family started using the internet around the year 2000. How about you? When did you start using the internet?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;互联网的第一个版本是在20世纪60年代创建的。这是一个原型。原型是一个产品的早期模型。所以，互联网的原型就是互联网的早期版本。它在美国被创造出来，美国政府启动了这个项目。但那个互联网和今天的互联网不一样。万维网是在1989年创建的。人们直到后来才有了家用互联网。例如，我的家庭大约在2000年左右开始使用互联网。你呢？你什么时候开始使用互联网的？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, now let&apos;s talk about the benefits of the internet. The internet is one of the most important inventions; it changed the world. Before the internet, there were fewer ways to communicate with people who were far away. You could call them on the phone, or you could write them a letter. I remember writing letters when I was a kid, but nowadays, most people don&apos;t write letters anymore. We write emails or we send text messages. Thanks to the internet, we can send messages instantly. So communication is faster and easier.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;现在让我们谈谈互联网的好处。互联网是最重要的发明之一；它改变了世界。在互联网之前，与远方的人交流的方式较少。你可以给他们打电话，或者给他们写信。我记得小时候写信，但现在大多数人不再写信了。我们写电子邮件或者发送短信。多亏了互联网，我们可以即时发送信息。因此，交流变得更快、更容易。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Nowadays many people can have long-distance relationships because of the internet. You can talk to your boyfriend or girlfriend for free using Skype or other apps. For that reason, it&apos;s easier to have a long-distance relationship nowadays. It&apos;s still hard, of course, but the internet makes it a little easier.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;如今，由于互联网的存在，许多人可以拥有远距离恋爱关系。你可以使用Skype或其他应用程序免费与你的男朋友或女朋友交谈。因此，现在拥有一段远距离恋爱关系变得更容易了。当然，这仍然很难，但互联网让它变得稍微容易了一些。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Another benefit of the internet is the information it contains. You can find anything and everything on the internet. If you want to learn about something, it&apos;s super easy. You just need to search for that subject on the internet. There are so many useful resources online.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;互联网的另一个好处是它所包含的信息。你可以在互联网上找到任何东西。如果你想了解某件事，那非常容易。你只需要在互联网上搜索那个主题。网上有很多有用的资源。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, now let&apos;s talk about some of the negative effects of the internet. For example, there&apos;s a lot of bad content on the internet. Not everything is good and helpful. There are a lot of things online that we should avoid. Parents need to be careful because children can find anything online.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，现在让我们谈谈互联网的一些负面影响。例如，互联网上有很多不良内容。并不是所有的东西都是好的和有帮助的。网上有很多我们应该避免的东西。家长们需要小心，因为孩子们可以在网上找到任何东西。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Another negative thing is that people spend a lot of time on the internet. Many of us spend hours and hours every day on the computer. We should spend more time outside, but we don&apos;t. We&apos;re addicted to the internet. One other negative effect of the internet is that our relationships can get worse.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;另一个不好的方面是人们在互联网上花费了大量时间。我们中的许多人每天在电脑上花费数小时。我们应该花更多时间在户外，但我们没有。我们对互联网上瘾了。互联网的另一个负面影响是我们的人际关系可能会变差。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now it&apos;s less common to talk to people in person. We usually talk to people online. This means that many children don&apos;t learn good communication skills, and sometimes people can get in arguments online. People often argue on Facebook or other social media apps.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;现在面对面与人交谈变得不那么常见了。我们通常在网上与人交流。这意味着许多孩子没有学习到良好的沟通技巧，有时人们在网上可能会发生争执。人们经常在Facebook或其他社交媒体应用上争吵。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Alright, let me teach you a few vocabulary words related to the internet. We use the phrase &quot;login&quot; or &quot;log into&quot; when we enter an account like Facebook. And we use the phrase &quot;log out&quot; when we exit. So you can say, &quot;I logged into Facebook&quot; or &quot;I logged out of Facebook.&quot;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，让我教你一些与互联网相关的词汇。当我们登录像Facebook这样的账户时，我们使用“login”或“log into”这个短语。当我们退出时，我们使用“log out”这个短语。所以你可以说，“我登录了Facebook”或者“我退出了Facebook”。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now let&apos;s look at the word &quot;username.&quot; This is the name that you use to log into an account. You use your username and password to log in. For example, my username is &quot;EnglishTeacher123.&quot; Lastly, let&apos;s look at the word &quot;browser.&quot; A browser is what you use to open web pages. Some examples of browsers are Safari and Google Chrome.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;现在让我们来看看“用户名”这个词。这是你用来登录账户的名字。你使用你的用户名和密码来登录。例如，我的用户名是“EnglishTeacher123”。最后，让我们来看看“浏览器”这个词。浏览器是你用来打开网页的工具。一些浏览器的例子包括Safari和Google Chrome。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, now I&apos;m gonna ask you some questions about the video to see if you understood. Write your answers in a comment down below:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;现在让我们来看看“用户名”这个词。这是你用来登录账户的名字。你使用你的用户名和密码来登录。例如，我的用户名是“EnglishTeacher123”。最后，让我们来看看“浏览器”这个词。浏览器是你用来打开网页的工具。一些浏览器的例子包括Safari和Google Chrome。&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;When was the World Wide web invented?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;What is one app you can use to talk to people far away?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;What is one negative effect of the internet?&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Alright, remember to subscribe to the channel, click on the bell, and follow us on Instagram for more English tips and lessons. I&apos;ll see you next time.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Winter Vocabulary and Activities for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-winter-vocabulary-activities-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-winter-vocabulary-activities-a1-beginners/</guid><pubDate>Wed, 14 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=21&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak. Before we start, remember to download the Listening Time podcast and become a member at &lt;a href=&quot;http://patreon.com/&quot;&gt;patreon.com&lt;/a&gt; slash listening time to receive my listening practice seminars.&lt;/p&gt;
&lt;p&gt;大家好，欢迎观看初级英语听力视频，你可以用这个视频练习英语听力和理解能力。在开始之前，点赞、关注、评论一键三连。&lt;/p&gt;
&lt;p&gt;Okay, today we&apos;re gonna talk about winter. This isn&apos;t my favorite topic because I prefer other seasons, but it&apos;s winter now, so let&apos;s talk about it. In most places, the weather is cold during winter. I don&apos;t live in a very cold area, but I still feel uncomfortable during this season. I don&apos;t have a heating system in my apartment. This means that my apartment isn&apos;t warm during winter. So we have to use extra blankets and wear warm clothes inside. And of course, every time we go outside, we have to wear warm clothes too.&lt;/p&gt;
&lt;p&gt;今天我们要谈论冬天。这不是我最喜欢的话题，因为我更喜欢其他季节，但现在是冬天，所以让我们来谈谈它。在大多数地方，冬天的天气很冷。我不住在非常寒冷的地区，但在这个季节我仍然感到不舒服。我的公寓里没有供暖系统。这意味着我的公寓在冬天不温暖。所以我们不得不使用额外的毯子，在里面穿上暖和的衣服。当然，每次我们外出时，我们也得穿上暖和的衣服。&lt;/p&gt;
&lt;p&gt;In my city, we often have cloudy weather or sometimes rainy weather during this season. I don&apos;t like this, but the worst part of winter is that the days are shorter. The sun goes down really early. Normally in the summer, the sun sets around 7:30 or 8pm in my city. However, in December, it sets before 5pm many people don&apos;t like this because they don&apos;t have many opportunities to enjoy this sunlight. When they finish working, it&apos;s already dark outside. This can be depressing. I try to start working early in the morning so I can finish early. This way I can have some hours of sunlight after I&apos;m done with work. In general, I love the sun, so I prefer long summer days, not short winter days.&lt;/p&gt;
&lt;p&gt;在我的城市，这个季节我们经常有多云的天气，有时还会下雨。我不喜欢这样，但冬天最糟糕的部分是白天变短了。太阳很早就下山了。通常在夏天，我城市的太阳大约在晚上7点半或8点落山。然而，在12月，太阳在下午5点之前就落山了，很多人不喜欢这样，因为他们没有太多机会享受阳光。当他们下班时，外面已经很黑了。这可能会让人感到沮丧。我尽量在早上早点开始工作，这样我就能早点完成。这样我下班后还能享受几个小时的阳光。总的来说，我喜欢太阳，所以我更喜欢漫长的夏日，而不是短暂的冬日。&lt;/p&gt;
&lt;p&gt;Okay, now let&apos;s talk about some winter activities. Of course, some of the funnest winter activities involve snow or ice. For example, it&apos;s common to go skiing or snowboarding during this time. In the US, there are many ski resorts where people can practice these sports. If you don&apos;t know how to ski or snowboard, you can also try sledding. Sledding is the activity where you sit on something and slide down a hill. It&apos;s easy and fun.&lt;/p&gt;
&lt;p&gt;现在让我们来谈谈一些冬季活动。当然，一些最有趣的冬季活动涉及到雪或冰。例如，这个时候去滑雪或单板滑雪是很常见的。在美国，有很多滑雪场，人们可以在这些地方练习这些运动。如果你不会滑雪或单板滑雪，你也可以尝试雪橇。雪橇是一种你坐在某物上然后滑下山坡的活动。它既简单又有趣。&lt;/p&gt;
&lt;p&gt;Another fun thing you can do in the snow is have a snowball fight. This is where you throw balls of snow at other people. Everyone likes throwing snowballs at people.&lt;/p&gt;
&lt;p&gt;在雪地里你可以做的另一件有趣的事是打雪仗。这就是你把雪球扔向其他人。大家都喜欢向人扔雪球。&lt;/p&gt;
&lt;p&gt;One other winter sport is ice skating. There are many places to ice skate in the US, even in the middle of big cities. I&apos;m terrible at ice skating, but I still think it&apos;s fun. The only bad part is when you fall because it hurts. Trust me.&lt;/p&gt;
&lt;p&gt;另一种冬季运动是滑冰。在美国，即使在大城市的中心，也有很多滑冰的地方。我滑冰很糟糕，但仍然觉得很有趣。唯一的不好之处就是当你摔倒时，因为那会很疼。相信我。&lt;/p&gt;
&lt;p&gt;Okay, now let&apos;s talk about winter holidays and traditions. For me, the best part of winter is Christmas. I don&apos;t usually like holidays, but I love Christmas. My family had several Christmas traditions that I&apos;ll always remember. For example, we always decorated the Christmas tree together with the same ornaments every year.&lt;/p&gt;
&lt;p&gt;好的，现在让我们谈谈冬季假期和传统。对我来说，冬季最好的部分是圣诞节。我通常不喜欢假期，但我爱圣诞节。我的家庭有几个我将永远记得的圣诞传统。例如，我们总是每年一起用相同的装饰品装饰圣诞树。&lt;/p&gt;
&lt;p&gt;Another tradition that I like is going to see the beautiful lights and decorations in different neighborhoods. I&apos;m excited to start new Christmas traditions with my own family. Many people around the world also celebrate New Year&apos;s Eve. In the US, a lot of people turn on the TV to watch the New Year&apos;s Eve party in New York City. I did this when I was younger, but nowadays this holiday isn&apos;t really important to me.&lt;/p&gt;
&lt;p&gt;我喜欢的另一个传统是去不同社区欣赏美丽的灯光和装饰。我期待着与自己的家人开始新的圣诞节传统。世界各地的许多人也庆祝除夕夜。在美国，很多人会打开电视观看纽约市的除夕夜派对。我年轻时这样做过，但现在这个节日对我来说并不那么重要了。&lt;/p&gt;
&lt;p&gt;I like Christmas, but not New Year&apos;s Eve. However, when I&apos;m with my wife&apos;s family, I have to celebrate this holiday with them.&lt;/p&gt;
&lt;p&gt;我喜欢圣诞节，但不喜欢新年前夕。然而，当我和妻子的家人在一起时，我必须和他们一起庆祝这个节日。&lt;/p&gt;
&lt;p&gt;Okay, that&apos;s all for today. Leave a comment and tell me your favorite thing about winter before you go, remember to download the Listening Time podcast and become a member at &lt;a href=&quot;http://patreon.com/&quot;&gt;patreon.com&lt;/a&gt; slash listening time to receive my Listening Practice seminars. Also, subscribe to the channel, click on the bell and follow us on Instagram. I&apos;ll see you next time.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Technology Vocabulary for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-technology-vocabulary-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-technology-vocabulary-a1-beginners/</guid><pubDate>Tue, 13 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=20&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak. Before we start, remember to subscribe to the channel, click on the bell, and follow us on Instagram.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家好，欢迎关注初级英语听力视频，你可以用这个视频练习英语听力和理解能力。在开始之前，记得点赞、关注、评论一键三连。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You ready? So today, I&apos;m going to talk about technology. This is a great topic because we all use technology every day. You&apos;re using technology to watch this video right now. So let&apos;s talk about some different kinds of technology today.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;准备好了吗？今天，我将谈论技术。这是一个很棒的话题，因为我们每个人每天都使用技术。你现在就在使用技术观看这个视频。那么，让我们今天讨论一些不同类型的技术吧。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One really important type of technology is computer technology. Computers today are much different than computers from the past. 20 or 30 years ago, computers were really limited. They couldn&apos;t do the things that computers do today. In the past, they were also really big. But today, computers come in many different sizes. Computers today are fast, powerful, and easy to use.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;一种真正重要的技术是计算机技术。今天的计算机与过去相比有很大的不同。20或30年前，计算机的功能非常有限。它们不能做现在计算机能做的事情。过去，计算机体积也相当庞大。但今天，计算机有多种不同的尺寸。现在的计算机速度快、功能强大且易于使用。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I remember when I first started using the computer, I was 6 years old. I liked playing computer games, but all of the games were very basic at that time. I still thought they were really fun. Today, computer games are very complex.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我记得我六岁开始使用计算机时，我喜欢玩电脑游戏，但那时所有的游戏都非常基础。尽管如此，我仍然觉得它们非常有趣。如今，电脑游戏非常复杂。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Alright, now let&apos;s talk about cell phones. When I was a kid, not many people had cell phones. Most people used landlines, which are phones inside your house. Nowadays, not many people have landlines. Everyone has cell phones now. I remember getting my first cell phone when I was 12 years old. I thought it was so cool. These days, phones are extremely important, because you can do almost anything on your phone.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，现在我们来谈谈手机。我小时候，有手机的人并不多。大多数人使用的是有线电话，就是家里的那种电话。现在，拥有有线电话的人不多了。现在每个人都有手机。我记得我12岁的时候得到了我的第一部手机。我觉得它非常酷。如今，手机非常重要，因为你几乎可以在手机上做任何事情。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;But I think the most important technology today is the internet. Most people use the internet every day to do many things. People like me need the internet in order to work. If I don&apos;t have the internet, I can&apos;t work. We also use the internet to study, to shop, and to entertain ourselves. I can&apos;t imagine not having the internet. I use it for many hours every day. How about you? How many hours a day do you use the internet?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;但我认为今天最重要的技术是互联网。大多数人每天都会使用互联网来做许多事情。像我这样的人需要互联网才能工作。如果没有互联网，我就不能工作。我们还使用互联网来学习、购物和娱乐自己。我无法想象没有互联网的生活。我每天会使用它很多个小时。你呢？你每天使用互联网多少小时？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, now let&apos;s talk about technology of the past. For example, one really important invention was the motorized vehicle, or the car. Before cars, people traveled by horse, by foot, or in other ways. When the car was invented, people were able to travel more easily. Cars from the past looked very different from today&apos;s cars. I think old cars look pretty cool.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;现在让我们来谈谈过去的技术。例如，一个非常重要的发明是机动车辆，或者说是汽车。在汽车出现之前，人们通过骑马、步行或其他方式出行。当汽车被发明出来后，人们能够更轻松地旅行。过去的汽车看起来与今天的汽车非常不同。我认为老式汽车看起来相当酷。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Another really important invention was electricity. Before electricity, people had to use candles and fire for light at night. At night, the cities were much darker than today. Nowadays, our cities have so much light at night. And of course, we use electricity for so many different things today. Sometimes the electricity goes out, and everything stops working. I hate when the electricity goes out.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;另一个非常重要的发明是电。在有电之前，人们晚上不得不使用蜡烛和火把来照明。那时候，城市的夜晚比现在要暗得多。如今，我们的城市在夜晚有如此多的光亮。当然，今天我们使用电来做许多不同的事情。有时候电力会中断，一切都停止工作。我讨厌电力中断的时候。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One more important invention was the television. In the past, television was the greatest form of entertainment. Everyone sat down in the evenings and watched TV. Nowadays, more people watch TV shows on their computers, like on Netflix. Many young people prefer doing everything on their computer or cell phone.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;又一项重要的发明是电视。在过去，电视是娱乐的主要形式。每个人晚上都会坐下来看电视。现在，更多的人在电脑上观看电视节目，比如在Netflix上。许多年轻人更喜欢在电脑或手机上做任何事情。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Alright, that&apos;s all for today. Leave a comment and tell me what your favorite technology is. And remember to subscribe to the channel, click on the bell, and follow us on Instagram for more English tips and lessons. I&apos;ll see you next time.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Working from Home Vocabulary for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-working-from-home-vocabulary-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-working-from-home-vocabulary-a1-beginners/</guid><pubDate>Mon, 12 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=19&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak week. Before we start, remember to download my Listening Time Podcast and become a Listening Time member at patreon.com slash listening time to receive my listening practice seminars, sound training videos, and bonus podcast episodes.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家好，欢迎观看初级英语听力视频，你可以用这个视频练习英语听力和理解能力。在开始之前，记得点赞、评论、关注一键三连。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, today we&apos;re gonna talk about working from home. This is a good topic because many people work remotely nowadays. Working remotely means you don&apos;t work in an office, you stay home and you use your computer or other technology to work. I work from home and I think there are positives and negatives to this. Let&apos;s talk about them.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;今天我们要聊聊在家工作。这是一个好话题，因为现在很多人远程工作。远程工作意味着你不是在办公室工作，你待在家里，使用你的电脑或其他技术来工作。我在家工作，我认为这样做有优点也有缺点。让我们来聊聀它们。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;First, let&apos;s start with the positives. If you work from home, you don&apos;t need to commute to work. You don&apos;t have to drive to work in the morning or drive back home in the evening. This is great because you don&apos;t have to worry about traffic in the morning and in the evening. There are many cars on the road because many people are commuting to and from work. Some people get stuck in this traffic every day.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;首先，让我们从积极的一面开始。如果你在家工作，你不需要通勤上班。你早上不需要开车去上班，晚上也不需要开车回家。这很棒，因为你不需要担心早晚的交通。路上有很多车，因为很多人正在上下班通勤。有些人每天都会陷入这种交通中。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is one of my favorite things about working from home. It saves you a lot of time. Another thing is that you can feel more relaxed when you work from home. You can wear casual clothes, you can take breaks when you&apos;re tired, and you can work in any room. I feel pretty comfortable working from home. It&apos;s not too formal and I feel free. If you work in an office, there are more rules and it&apos;s less comfortable.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;这是我在家工作最喜欢的事情之一。它可以为你节省很多时间。另一点是，在家工作时你可以感到更加放松。你可以穿休闲装，累了可以休息，而且你可以在任何房间工作。我觉得在家工作非常舒适。它不那么正式，我感到自由。如果你在办公室工作，规则更多，舒适度也较低。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One other positive about working from home is being able to spend more time with your family. For example, if you have a break, you can go in the other room and spend time with your family. When you work at an office, you don&apos;t have your family with you, so you can&apos;t do this. I love eating breakfast or lunch with my family when I have breaks. This is probably the best part about working from home. I can spend a lot of time with my family on weekdays and weekends.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;在家工作的一个额外好处是能够花更多时间与家人在一起。例如，如果你休息，你可以去另一个房间和家人共度时光。当你在办公室工作时，你的家人不在你身边，所以你无法这样做。我喜欢在休息时和家人一起吃早饭或午饭。这可能是在家工作最好的部分。在工作日和周末，我可以和家人共度很多时间。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, now let&apos;s talk about the negatives of working from home. One bad thing is that it&apos;s easy to get distracted at home. For example, if you have young children at home with you, it can be hard to focus on your work. Children make noise and interrupt you while you&apos;re working. This is normal. So you have to learn to manage these situations and stay focused on your work.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，现在我们来谈谈在家工作的缺点。一个不好的地方是在家容易分心。例如，如果你家里有年幼的孩子，那么专注于工作可能会很困难。孩子们会发出噪音并在你工作时打扰你。这是正常的。所以你必须学会管理这些情况，保持对工作的专注。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Another negative thing about working from home is that, sometimes you don&apos;t know when to stop working. When you work at an office, you stop working when you leave the office, you know exactly when your workday is done. However, when you work from home, it can be hard to know when to stop each day. You don&apos;t have your boss there to tell you when to stop.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;在家工作的另一个不利之处是，有时候你不知道何时该停止工作。当你在办公室工作时，你离开办公室时就停止工作，你知道你的工作日何时结束。然而，当你在家工作时，很难知道每天何时该停下来。你没有老板在那里告诉你何时该停止。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One more negative thing about working from home is not having contact with other people. In general, it&apos;s important to talk and interact with other people. If you work from home, you only talk to your coworkers on the computer or on the phone. This is okay, but I think it&apos;s also good to interact with people in person. It feels good to be around people and to work with people. So in general, I like working from home, but it&apos;s not perfect.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;在家工作的一个负面因素是缺乏与他人的接触。通常，与他人交谈和互动是很重要的。如果你在家工作，你只会在电脑上或电话上与同事交谈。这没问题，但我认为面对面与人互动也很好。在人群中感觉很好，与人们一起工作也很好。因此，总的来说，我喜欢在家工作，但它并不完美。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, that&apos;s all for today. Leave a comment and tell me if you like working from home. Before you go, remember to download the Listening Time podcast. And if you want to improve your listening, become a member at patreon.com slash listening time to receive my listening practice seminars, sound training videos, and bonus podcast episodes. Also, subscribe to the channel, click on the bell and follow us on Instagram. I&apos;ll see you next time.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Summer Activities and Vocabulary for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-summer-activities-vocabulary-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-summer-activities-vocabulary-a1-beginners/</guid><pubDate>Sun, 11 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=18&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot;  autoplay=&quot;true&quot;  muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak. And remember to sign up for our $1 Listening Practice seminars at polyglossa.com and download our free Listening Time podcast so you can practice your listening skills.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家好，欢迎观看初级英语听力视频，你可以用这个视频练习英语听力和理解能力。记得点赞、关注、评论一键三连。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So today, I&apos;m gonna talk about summer for some of you, it&apos;s summer now, and for others, it&apos;s winter. Here where I live, it&apos;s the summer season now.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;今天，我要聊的是夏天，对你们中的一些人来说，现在是夏天，而对其他人来说，现在是冬天。在我住的地方，现在是夏季。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So first, let&apos;s talk about summer weather. In most countries, this is the hottest time of year. In cold countries, summer is the only time of year when it&apos;s hot. In tropical countries, there isn&apos;t much difference between the seasons, but summer is definitely hot.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;首先，让我们来聊聊夏天的天气。在大多数国家，这是一年中最热的时候。在寒冷的国家，夏季是一年中唯一热的时候。在热带国家，季节之间没有太大差异，但夏季绝对很热。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I really like hot, sunny weather. Some people don&apos;t like this weather, so they prefer other seasons. How about you? Do you prefer hot or cold weather? Also, in some places, summer is the rainy season. Where I live now, it rains a lot in the summer. I don&apos;t like this. I grew up in Southern California where it doesn&apos;t rain a lot. So I&apos;m used to blue skies and sunny weather. For me, rainy weather isn&apos;t fun. I like to go outside and do activities, but it&apos;s hard to do this when it&apos;s raining.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我非常喜欢热天、晴朗的天气。有些人不喜欢这种天气，所以他们更喜欢其他季节。你呢？你喜欢炎热还是寒冷的天气？此外，在一些地方，夏天是雨季。我现在住的地方，夏天雨水很多。我不喜欢这样。我在南加州长大，那里雨水不多。所以我习惯了蓝天和晴朗的天气。对我来说，雨天很没意思。我喜欢外出进行活动，但在下雨的时候很难做到这一点。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Let&apos;s talk about some summer activities that people like to do. During the hot summer days. Many people like going to the beach. The water is usually warmer during this season, so it&apos;s a good time to swim. Some people like to lie on the sand and enjoy the hot sun, but I don&apos;t do this. I sometimes like swimming at the beach, but I definitely don&apos;t sunbathe. I get sunburned very easily.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;让我们来聊聊人们喜欢在夏天做的一些活动。在炎热的夏日里，许多人喜欢去海滩。这个季节的水通常比较温暖，所以是游泳的好时机。有些人喜欢躺在沙滩上享受炎热的阳光，但我不这么做。我有时会喜欢在海滩上游泳，但我绝对不会晒太阳。我很容易晒伤。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Another thing that many Americans do in the summer is have barbecues. This season is perfect for barbecues, because you can spend the afternoon outside with your family and friends. The kids can run around and play while the adults relax and talk. And of course, everyone enjoys eating good food at barbecues. I love eating hamburgers and hot dogs outside on warm from summer days.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;许多美国人在夏天做的另一件事是举办烧烤。这个季节非常适合烧烤，因为你可以在户外与家人和朋友一起度过下午。孩子们可以跑来跑去玩耍，而成年人则可以放松和交谈。当然，每个人都喜欢在烧烤时享用美食。我喜欢在温暖的夏日户外吃汉堡和热狗。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Also, many Americans have swimming pools, so the summer months are a great time to use them. When I was a kid, my family always went in the pool during this time of year. I have great memories of playing with my sister and my friends in our pool. It&apos;s always fun to go in the pool during the summer. People who don&apos;t have swimming pools can go to public pools. In big cities, there are usually public swimming pools where you can go during the summer or during other months.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;此外，许多美国人拥有游泳池，因此夏季是使用它们的绝佳时机。我小时候，我的家人总是在这个时间里去游泳池。我对我们在游泳池里和我的妹妹还有朋友们玩耍的美好回忆。在夏天去游泳池总是很有趣的。没有游泳池的人可以去公共游泳池。在大城市里，通常有公共游泳池，你可以在夏天或其他月份去那里。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One other popular summer activity in the US is camping. Summer is the perfect time to go camping, because you don&apos;t get too cold at night. Usually people sleep outside in tents when they camp. So it&apos;s better to do this activity when it&apos;s warm. I&apos;ve camped in the summer and in the winter, but it&apos;s definitely better in the summer. A lot of people go hiking when they camp, which is also better in the summer, in my opinion.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;另一种在美国流行的夏季活动是露营。夏天是去露营的完美时机，因为晚上你不会太冷。通常人们露营时会睡在帐篷里。所以最好在温暖的时候进行这项活动。我夏天和冬天都露营过，但绝对是夏天更好。很多人露营时会去远足，在我看来，夏天更合适。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;All right, now let&apos;s talk about summer vacation in the US, children usually have a long break from school during the summer. When I was in elementary school and middle school, I had two and a half months of summer vacation. The school year ended in the middle of June, and the next school year began in September. This is a long break. I had time to do many things during these months. Many American children go to summer camp during this break. There are many types of summer camps where kids do fun activities, learn new things and spend time outdoors. I went to a few sports summer camps when I was a kid. Also, many people travel during this season, because children don&apos;t have to go to school.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，现在让我们来谈谈美国的暑假，孩子们在夏天通常有一段长时间的学校假期。当我在小学和中学的时候，我有两个月半的暑假。学期在六月中旬结束，下个学期在九月份开始。这是一个很长的假期。在这几个月份里，我有时间做很多事情。许多美国孩子在这段时间里去夏令营。有很多类型的夏令营，孩子们在那里进行有趣的活动，学习新东西，并且花时间在户外。当我还是个孩子的时候，我去过几个体育夏令营。此外，很多人在这个季节旅行，因为孩子们不用上学。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Summer is also a good time to travel because of the good weather. But the bad thing about traveling in the summer is that many touristic places are crowded at this time. This means that there are many people there, so I prefer to travel during other seasons.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;夏天也是旅行的好时机，因为天气好。但是夏天旅行的缺点是许多旅游景点在这个时候都很拥挤。这意味着那里有很多人，所以我更喜欢在其他季节旅行。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;All right, now I&apos;m gonna ask you some questions about the video to see if you understood. Write your answers in a comment down below.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，现在我要问你一些关于视频的问题，看看你是否理解了。把你的答案写在下面的评论中。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;No. 1, what&apos;s one summer activity?&lt;/p&gt;
&lt;p&gt;No.2, where do people sleep when they go camping?&lt;/p&gt;
&lt;p&gt;No. 3, what&apos;s one bad thing about traveling during the summer?&lt;/p&gt;
&lt;p&gt;Okay, before we go, remember to sign up for our $1 Listening Practice seminars and download the Listening Time podcast so you can practice your listening skills. And of course, subscribe to the channel, click on the bell and follow us on Instagram. I&apos;ll see you next time.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Organization Tips and Vocabulary for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-organization-tips-vocabulary-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-organization-tips-vocabulary-a1-beginners/</guid><pubDate>Sat, 10 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=17&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey English learners, welcome to this A1 English listening practice video. You can use this video to practice your listening and learn new words and phrases.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家好，欢迎观看初级英语听力视频，你可以用这个视频练习听力和新的单词和词组。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Today we&apos;re gonna talk about being organized. This is an important topic. If we&apos;re organized, it makes our lives easier.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;今天，我们要讨论如何变得有条理。这是一个重要的话题。如果我们有条理，我们的生活就会更加轻松。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Before we start, remember to download my free Listening Time podcast on Spotify, Apple Podcasts, or any other podcast app so you can practice your English. The link is in the description below.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;在开始之前，记得点赞、关注、评论一键三连。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, let&apos;s talk about being organized. You might wonder why this is important. Well, being organized helps us feel less stressed and more in control. Let&apos;s talk about a few ways we can be more organized.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，我们来聊聊如何变得有条理。你可能想知道为什么这很重要。嗯，有条理有助于我们感到压力更小，更有掌控感。让我们聊聊几种能让我们变得更有条理的方法。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;First, it&apos;s helpful to make lists. Lists are like your map for the day. You can write down what you need to do, like chores or homework. This helps you remember everything and feel more organized. And it feels great to check things off your list when you&apos;re done with them. It&apos;s also important to set priorities. This means deciding what&apos;s most important and doing those things first.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;首先，制作清单很有帮助。清单就像是你一天的地图。你可以写下你需要做的事情，比如家务或作业。这有助于你记住所有事情并感觉更有条理。当你完成它们时，从清单上划掉它们的感觉很棒。同时，设定优先级也很重要。这意味着决定什么是最重要的，然后首先去做这些事情。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So you can look at your list and see which tasks need to be prioritized. This helps you manage your time better and not feel overwhelmed.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;所以你可以查看你的清单，看看哪些任务需要优先处理。这有助于你更好地管理你的时间，不会感到不知所措。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Keeping your room and your workspace tidy is important, too. Imagine trying to find something in a messy room — It&apos;s hard.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;保持你的房间和工作空间整洁也很重要。想象一下在一间乱糟糟的房间里找东西——这很难。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Keeping your bedroom, your office and your desk tidy helps you find things more easily. It also helps you feel calmer and more focused.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;保持你的卧室、办公室和书桌整洁有助于你更容易找到东西。它也能让你感觉更平静、更专注。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Another thing that can help you be organized is using a calendar. This can help you remember important dates, like birthdays and appointments. You can write these things on the calendar so that you don&apos;t forget. You can also use your calendar on your phone and set reminders there. This is a fantastic way to stay organized.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;另一件事可以帮助你保持有条理，那就是使用日历。这可以帮助你记住重要的日子，比如生日和约会。你可以在日历上写下这些事情，这样你就不会忘记。你也可以使用手机上的日历并在那里设置提醒。这是保持有条理的绝佳方式。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And lastly, one other tip is to plan ahead. If you plan your next day or your next week, you&apos;ll know what to do on those days. If you don&apos;t have a plan, you might feel disorganized and you might not know what you need to do. So having a plan that you can follow can really help. So those are some easy ways to keep your life organized every day, making lists, setting priorities, keeping your space tidy, using a calendar, and planning ahead. If you do all of this, you might feel less stressed and more in control.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;最后，另一个建议是提前计划。如果你计划好第二天或下一周，你就会知道那些日子该做什么。如果你没有计划，你可能会感到无组织，你可能不知道你需要做什么。因此，有一个你可以遵循的计划真的可以提供帮助。所以，这些是保持你的生活每天有序的一些简单方法：制作清单，设定优先级，保持你的空间整洁，使用日历，提前计划。如果你做到所有这些，你可能会感觉压力更小，更有控制感。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Let&apos;s review some of the words in this video that I used that might be new for you. The word &quot;chores&quot; refers to tasks that you do at home, like doing the laundry and cleaning the bathroom.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;让我们回顾一下这个视频中我使用的一些可能对你们来说是新词的词汇。“chores” 这个词指的是你在家里做的一些任务，比如洗衣服和清洁浴室。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The phrase &quot;check things off your list&quot; means that you have a list of tasks to do, and when you finish them, you make a Mark like this on your list.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&quot;check things off your list&quot; 这个短语意味着你有一张任务清单，当你完成它们时，你会在你的清单上做一个像这样的标记。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;When you feel &quot;overwhelmed&quot;, this means that you feel bad because you can&apos;t handle something. It&apos;s too much for you.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;当你感到 “overwhelmed” 时，这意味着你因为无法处理某件事而感到糟糕。这对你来说太多了。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The word &quot;tidy&quot; means organized and clean. You should try to keep your room tidy.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;“tidy” 这个词意味着整洁有序。你应该尽量保持你的房间整洁。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And &quot;messy&quot; means the opposite. This means that things are disorganized and not clean.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;而 “messy” 意味着相反。这意味着事物是无组织的，不干净的。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, I hope you enjoyed this Listening Practice video. Remember to download my free Listening Time podcast if you wanna practice your English. The link is in the description below. And you can also join my membership if you want my training to help you understand fast English. The link to that is also down below. Alright, thank you for watching and I&apos;ll talk to you in the next video.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Free Time Activities Vocabulary for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-free-time-activities-vocabulary-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-free-time-activities-vocabulary-a1-beginners/</guid><pubDate>Fri, 09 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=16&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak. Before we start, remember to subscribe to the channel, click on the bell, and follow us on Instagram. You ready?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家好，欢迎观看初级英语听力视频，你可以用这个视频练习英语听力和理解能力。正式开始之前，点赞、关注、评论一键三连。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So today I&apos;m gonna talk about free time. This is a good topic because everyone enjoys having free time. I love having free time and you probably do too.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;今天我要谈谈空闲时间。这是一个好话题，因为每个人都喜欢有空闲时间。我喜欢有空闲时间，你大概也喜欢。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So first, let&apos;s talk about how much free time people have. Most children have more free time than adults. When you&apos;re a kid, you don&apos;t have the responsibilities that an adult has. Adults have to work, pay the bills, and take care of their children. Kids usually don&apos;t have to do these things. Kids usually have to go to school and do homework. This can be difficult, but it&apos;s usually not that difficult. So children have more free time.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;首先，让我们来谈谈人们有多少空闲时间。大多数孩子比成年人有更多的空闲时间。当你是个孩子时，你没有成年人所承担的责任。成年人必须工作，支付账单，并照顾他们的孩子。孩子们通常不需要做这些事情。孩子们通常需要去上学和做家庭作业。这可能会有些困难，但通常并不那么困难。所以孩子们有更多的空闲时间。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;When I was a kid, I had a lot of free time. I got home from school around 2 or 3 pm, and after that, I played a lot on weekdays. From Monday to Friday, I probably had around four or five hours of free time each day. Sometimes I got bored because I had so much free time. But as I got older, I had more homework each year. So each year I had a little less free time. I didn&apos;t have too much homework, though. In the US, we don&apos;t get that much homework. In some other countries, children have a lot of homework.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;小时候，我有很多空闲时间。我大概下午两、三点放学回家，之后就是玩。从周一到周五，我每天大概有大约四到五个小时的自由时间。有时候我会因为空闲时间太多而感到无聊。但随着年龄的增长，我每年的作业也越来越多。所以，我每年的空闲时间都少一些。不过，我的作业并不算太多。在美国，我们不会有那么多作业。在一些其他国家，孩子们有很多作业。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I&apos;m glad that my school work wasn&apos;t very hard. On weekends, I had even more free time on Saturday and Sunday. I did many activities. Weekends were the best because I had all day to play and rest. I really liked weekends and I still do.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我很高兴我的学校作业并不很难。在周末，我甚至在周六和周日有更多的空闲时间。我做了很多活动。周末是最好的，因为我有整天的时间来玩和休息。我真的很喜欢周末，现在依然如此。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now that I&apos;m an adult, I don&apos;t have a lot of free time. I have to work and do many other things. I usually start working early, like at 7:00am or 7:30am. So I have to wake up around 6:00am. When I was a kid, I slept more. I usually slept for 8 hours every night. As an adult, I don&apos;t sleep 8 hours every night. I usually get seven hours or seven and a half hours of sleep. How about you? How many hours of sleep do you get? So after I finish work, I have some free time in the evening. However, I usually do some extra work or studying during this time. I have to make these YouTube videos and Instagram videos. And I also study foreign languages. At night, I have some free time to just relax. My wife and I spend the evenings together and enjoy this time.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;既然我已经成年了，我并没有太多的空闲时间。我必须工作，还得做许多其他事情。我通常很早就开始工作，比如早上7:00或7:30。所以我必须在早上6:00左右醒来。当我还是个孩子的时候，我睡得更多。我每晚通常睡8个小时。作为一个成年人，我每晚不睡8个小时。我通常睡七个小时或者七个半小时。你呢？你每晚睡几个小时？所以，当我完成工作后，晚上我有一些空闲时间。然而，我通常在这个时间做一些额外的工作或学习。我必须制作这些YouTube视频和Instagram视频。我也学习外语。晚上，我有一些空闲时间来放松。晚上，我和我的妻子一起度过，享受这段时间。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, now let&apos;s talk about some popular activities that people do in their free time. For example, many people like to play sports or exercise in their free time. When I was a kid, I played a lot of sports. I played basketball, baseball, tennis, soccer, football, and golf. I really liked playing sports in my free time. But as an adult, I don&apos;t play any sports. I&apos;m not very interested in playing sports nowadays. However, I exercise in my free time. I work out almost every day, but just for a short time. Other people spend a lot of time exercising.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，现在让我们谈谈人们在空闲时间做的一些流行活动。例如，许多人喜欢在空闲时间进行运动或锻炼。当我还是个孩子的时候，我玩了很多运动。我打篮球、棒球、网球、足球、美式足球和高尔夫球。我真的很喜欢在空闲时间活动。但作为一个成年人，我活动就少了。我现在对活动不是很感兴趣。不过，我在空闲时间锻炼。我几乎每天都健身，但只是很短的时间。其他人则花很多时间锻炼。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So another activity that people do in their free time is watch TV shows and movies. Many people do this in their free time. I know some people who watch many hours of TV every day. I don&apos;t watch a lot of TV or movies. I really like playing games in my free time. I play chess online, but I&apos;m not very good. I also like playing board games with my family. We play games like Katan and code names. Do you like playing board games?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;人们在空闲时间做的另一项活动是观看电视节目和电影。许多人在他们的空闲时间做这件事。我认识一些每天看很多小时电视的人。我不太看电视或电影。我非常喜欢在空闲时间玩游戏。我在线下棋，但我不太擅长。我也喜欢和家人一起玩桌游。我们玩像卡坦岛和代号这样的游戏。你喜欢玩桌游吗？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One last activity that most people do in their free time is surf the internet. This is probably the most common activity that people do. I spend a lot of time on the internet. Some days I spend too much time on the internet. It&apos;s not good to spend all day inside on the computer. We should try to go outside and do other activities too. But the internet is very entertaining, so it&apos;s easy to spend many hours surfing the web.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大多数人在空闲时间做的最后一项活动是上网冲浪。这可能是人们最常见的活动。我在网上花费了很多时间。有些日子我在网上花费的时间太多了。整天待在室内对着电脑不太好。我们应该尝试出去做其他活动。但互联网非常有趣，所以很容易在网上冲浪数小时。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, now I&apos;m gonna ask you some questions about the video to see if you understood. Write your answers in a comment down below.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，现在我要问你一些关于视频的问题，看看你是否理解了。把你的答案写在下面的评论中。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;No. 1, what time did I get home from school when I was a kid?&lt;/p&gt;
&lt;p&gt;No. 2, how many hours do I sleep each night?&lt;/p&gt;
&lt;p&gt;No. 3, what game do I like playing online?&lt;/p&gt;
&lt;p&gt;Alright, remember to subscribe to the channel, click on the bell, and follow us on Instagram for more English tips and lessons. I&apos;ll see you next time.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Talking About Favorites for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-talking-about-favorites-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-talking-about-favorites-a1-beginners/</guid><pubDate>Thu, 08 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=15&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家好，欢迎观看初级英语听力视频，你可以用这个视频练习英语听力和理解能力。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Before we start, remember to download the Listening Time podcast. And if you want my specialized training to help you improve your listening, then become a member at patreon.com slash listening time. And if you want my advanced podcast episodes, then become a listening time family member.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;正式开始之前，点赞、关注、评论一键三连。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, today we&apos;re gonna talk about some of my favorite things. We all like talking about things we like and I wanted to make a video about some things that I like.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;今天我想聊一些我喜欢的事情。我们都喜欢聊自己喜欢的事情。我想做一个这样的视频。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So first I want to talk about my favorite dessert. This is a really hard one for me to choose. I love a lot of desserts, and so it&apos;s hard for me to decide which one is my favorite. But I think that right now my favorite dessert is homemade chocolate chip cookies. Notice that I said homemade. There&apos;s a big difference between homemade cookies and cookies you buy from the store. In my opinion, homemade cookies are much better than other cookies. And the perfect homemade cookie is the chocolate chip cookie.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;首先，我想聊聊我最喜欢的甜点。对我来说，选择这个真的很难。我喜欢很多甜点，所以很难决定哪一个是我的最爱。但我认为现在，我最喜欢的甜点是自制巧克力豆饼干。注意我说了“自制”。自制饼干和从商店里买的饼干有很大的区别。在我看来，自制饼干比其他饼干要好得多。而完美的自制饼干就是巧克力豆饼干。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In the US, it&apos;s really common for families to make the this dessert together. Usually children help their parents prepare and bake these cookies. It&apos;s a fun activity for the family, and the result is delicious.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;在美国，家人们一起制作这种甜点真的很普遍。通常孩子们会帮助他们的父母准备和烘焙这些饼干。这是一项有趣的家庭活动，而且做出来的甜点非常美味。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, next, let me tell you about my favorite month of the year. This is another hard one, but I think that my favorite month is April. The reason is because I really like sunshine and long days in April. Winter is finally over. The days get longer and the weather gets warmer. I don&apos;t have to worry about cold weather or rain. This is perfect for me.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;接下来，让我告诉你我一年中最喜欢的月份。这也是个难题，但我认为我最喜欢四月。因为我真的很喜欢四月的阳光和长日。冬天终于结束了。白天变长了，天气变暖了。我不用担心寒冷的天气或下雨。这对我来说很完美。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, how about my favorite sport? My answer to this question has changed many times in my life. When I was a young kid, my favorite sport was basketball. I was a big fan of the Los Angeles Lakers, and I played basketball on many teams.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;来说说我最喜欢的运动怎么样？我在不同的年龄阶段喜欢不同的运动。我小时候，最喜欢的运动是篮球。我是洛杉矶湖人队的超级粉丝，我也在很多球队打过篮球。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;After that, my favorite sport was football. And I really liked this Seattle Seahawks for many years. Then my favorite sport became soccer, and I started watching it a lot. But now I don&apos;t know if I have a favorite sport. I don&apos;t really watch sports anymore. So it&apos;s hard to say. But I wanna mention my favorite sport to play. I&apos;ve played many sports in my life, but the funniest one for me is golf. In my opinion, it&apos;s the most challenging sport. It&apos;s really hard. But once you start to get better, it&apos;s really fun.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;在那之后，我最喜欢的运动是足球。我喜欢西雅图海鹰队很多年了。然后我最喜欢的运动变成了足球，我开始经常看。但现在我不知道我是否有最喜欢的运动。我不再真的看体育比赛了。所以很难说。但我想提一下我最喜欢的运动。我一生中玩过很多运动，但对我来说最有趣的是高尔夫。在我看来，这是最具挑战性的运动。它真的很难。但一旦你开始变得更好，它真的很有趣。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;All right. Lastly, let me talk about my favorite language that I&apos;ve studied. I like all the languages that I&apos;ve Learned, but the funniest one for me to study is Greek. The main reason why is because Greek has a different alphabet.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;最后，聊聊我学过的最喜欢的语言。我喜欢我学过的所有语言，但对我来说最有趣的是希腊语。主要原因是希腊语有一个不同的字母表。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I love the challenge of learning a completely new system. It&apos;s really cool to see Greek writing and be able to read it and understand it. I also really like the sound of the language. It&apos;s a beautiful language and it feels good to speak it.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我喜欢学习一个全新的系统所带来的挑战。能够阅读并理解希腊文书写真的很酷。我也非常喜欢这门语言的声音。它是一门美丽的语言，说起来感觉很好。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Currently, I don&apos;t study this language, so I&apos;ve forgotten almost everything, but I&apos;ll definitely start learning it again in the future.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;目前，我不在学习这门语言，所以我几乎忘记了所有的东西，但我将来一定会重新开始学习它。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Alright, I hope you enjoy this video. I also did a podcast episode about this topic, so you can listen to that if you wanna hear more. Before you go, remember to download the Listening Time podcast and become a member at patreon.com slash listening time to receive my specialized training to help you understand native speakers. And if you want to reach an advanced level of listening and become a listening time family member to receive my advanced podcast episodes. Also subscribe to the channel, click on the bell and follow us on Instagram. I&apos;ll see you next time.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Supermarket Vocabulary for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-supermarket-vocabulary-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-supermarket-vocabulary-a1-beginners/</guid><pubDate>Wed, 07 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=14&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak. Before we start, remember to subscribe to the channel, click on the bell, and follow us on Instagram. You ready?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家好，欢迎观看初级英语听力视频，你可以用这个视频练习英语听力和理解能力。在正式开始之前，点赞、关注、评论一键三连。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So today, I&apos;m going to talk about the supermarket. This is a useful topic because most people buy food from supermarkets. One important note: in the US, many people use the phrase &quot;grocery store&quot; instead of &quot;supermarket.&quot; I usually say &quot;grocery store,&quot; but you can use both.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;今天，我想聊聊超市。这是个很有用的主题，因为大家都去超市购买食物。有一点要说明一下，很多美国人用 &quot;grocery store&quot; 代替 &quot;supermarket&quot;。我一般也说 &quot;grocery store&quot;，但你都可以说。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So first, let&apos;s talk about big supermarkets. The most famous supermarket is Walmart. Walmart is really big and sells many items. They sell food, clothes, electronics, furniture, and much more. Walmart has everything. In big supermarkets, there are a lot of cheap items. Personally, I don&apos;t like big supermarkets. I prefer smaller supermarkets because they often have better products.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;首先，让我们聊聊大型超市。沃尔玛是最牛逼的大型超市。它真的很大什么都卖。食物、衣服、电子产品、家具等，什么都有。大型超市有很多便宜的商品。老实说，我不喜欢大型超市，我喜欢小超市因为那里有更好的商品。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I like to buy organic food, so I search for small organic stores. These stores are usually more expensive than big supermarkets. Organic food is more expensive than non-organic food, but I think it&apos;s worth the price.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我喜欢有机食物，所以我会找一些小的有机商品店。这些超市一般会比大型超市贵，有机食物比普通食物贵，但我觉得这个钱值得花。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In big supermarkets, I can&apos;t find the products I like. That&apos;s why I go to small local stores. There are also some very small supermarkets, too. We call these &quot;convenience stores.&quot; For example, 7-11 is a convenience store. These stores sell some food and drinks, but they don&apos;t have a lot of items. I go to convenience stores when I need to buy just one or two items, but I don&apos;t usually shop at convenience stores. They don&apos;t have all the items that I need.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我喜欢去本地小超市购物，因为大超市找不到想要的商品。有一些很小的商店我们称之为 “便利店”。比如：十足就是便利店。这些店卖一些食物和饮料，但它们的商品不多。当我只想买一两个东西时会去便利店，但我不经常在便利店消费。那里没有我想要的所有商品。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;How about you? Do you prefer big supermarkets, small supermarkets, or convenience stores? Some people don&apos;t go to supermarkets. They buy their groceries online. Nowadays, you can buy everything online. You order it, and someone brings it to your house. This is becoming a popular option. I order some items online, but I don&apos;t order food online.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;你呢？你喜欢去哪种商店购物？有些人不去实体店购物，他们在线上买东西。如今，你可以在线上买到任何东西，你在线上下单，有人给你送到家。这已经变成了很流行的购物方式。我也会在线上买一些东西，但不会买食物。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, now let&apos;s learn some important supermarket vocabulary. Our first vocabulary word is &quot;cart.&quot; When you enter a grocery store, you grab a cart. You put all of your items in your cart while you&apos;re shopping. Or if you&apos;re only buying a few items, you can use a basket, which you carry.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;现在，我们聊聊关于超市的词汇。第一个是 &quot;cart&quot;，当你进入一家杂货店时，你拿一辆购物车。你在购物时把所有商品都放进你的购物车。或者如果你只买几样东西，你可以使用一个篮子，你带着它。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Our next word is &quot;aisles.&quot; Aisles are the rows of products in a store. You walk up and down the aisles when you go shopping.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我们的下一个词汇是 &quot;aisles&quot; 。过道是商店里产品排列成的行。当你去购物时，你会在过道里来回走动。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The next phrase is &quot;on sale.&quot; When an item is on sale, this means that it has a lower price than normal. I love when items are on sale.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;下一句是 “on sale”。当一个商品打折时，这意味着它的价格比正常价格低。我喜欢商品打折的时候。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, one more word: &quot;cashier.&quot; The cashier is the person that you pay when you&apos;re done shopping. In the US, cashiers are usually friendly. Nowadays, in some supermarkets, you can pay without a cashier. This is called &quot;self-checkout.&quot; Some people prefer cashiers, and other people prefer the self-checkout option. I like both options.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，再来说一个词：“收银员”。收银员是你购物结束后要付款给的人。在美国，收银员通常都很友好。现在，在一些超市里，你可以不用收银员就完成支付。这叫做“自助结账”。有些人更喜欢收银员，而有些人则更喜欢自助结账的选项。我两种选择都喜欢。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Alright, that&apos;s all for today. Leave a comment and tell me where you buy your food. And remember to subscribe to the channel, click on the bell, and follow us on Instagram for more English tips and lessons. I&apos;ll see you next time.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Facts About the English Language for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-facts-about-english-language-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-facts-about-english-language-a1-beginners/</guid><pubDate>Tue, 06 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=13&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak. And remember to sign up for our $1 Listening Practice seminars at polyglaza.com, and download our free Listening Time podcasts so you can practice your listening skills.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家好，欢迎观看初级英语听力视频。你可以用这个视频练习英语听力和理解能力。别忘了点赞、关注、评论一键三连。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So today I&apos;m gonna talk about the English language. This is an important topic for all of you because you&apos;re all learning English in this video, I&apos;m gonna give you some interesting facts about the English language. This should be fun.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;今天我想聊聊英语。这是个对大家都很重要的话题，因为大家都通过这个视频学英语。我将告诉大家一些关于英语的有趣的事情。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, so the first thing I wanna talk about is how many people speak this language? Well, almost 400 million people speak English as their first language. These people are native English speakers. Most of these speakers are in the US, of course, but there are many other English speaking countries. Obviously, countries like the UK, Australia, Canada and Ireland speak English, but there are also a lot of other countries where people speak English. For example, English is the major language of Belize, Guyana, Jamaica, the Bahamas, and other countries too. There are a lot of English speaking countries. Also, many people around the world speak English as their second language. In every country, there are people who are learning English.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;首先我想聊聊到底有多少人在使用英语。大约有4亿人的母语是英语。这些人大部分在美国，当然，还有其他说英语的国家。显然，英国、澳大利亚、加拿大和爱尔兰都说英语，还有其他一些国家也说英语。例如，英语是伯利兹、圭亚那、牙买加、巴哈马以及其他国家的主要语言。有很多说英语的国家。此外，世界各地还有很多人将英语作为第二语言。每个国家，都有人正在学习英语的人。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As a teacher, I&apos;ve taught students from over 80 different countries. Cool. We don&apos;t know exactly how many people speak English as a second language, but there are a lot.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;作为一名教师，我教过来自80多个不同国家的学生。屌不屌。我们不知道确切有多少人将英语作为第二语言，但有很多人。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, now let&apos;s talk about the history of English. The first form of English appeared in the 5th century AD. Today we call this early English &quot;Old English&quot;. Old English was very different from modern English. I can&apos;t understand Old English. In the 11th century, Old English became &quot;Middle English&quot;. Middle English is a little closer to modern English, but it&apos;s still very different. Finally, modern English began at the end of the 14th century, but English continues to change. So today&apos;s English looks a little different from the English of the past few centuries.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，现在让我们谈谈英语的历史。英语的第一个形式出现在公元5世纪。今天我们称这种早期英语为“古英语”。古英语与现代英语非常不同。我无法理解古英语。在11世纪，古英语变成了“中古英语”。中古英语与现代英语稍微接近一些，但它仍然非常不同。最后，现代英语在14世纪末开始，但英语仍在继续变化。所以今天的英语与过去几个世纪的英语看起来略有不同。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Another important thing to know about English is that other languages have influenced it a lot. So, which languages? Well, for example, some experts say that almost 30% of English words come from Latin and almost 30% of English words come directly from French. That means that almost 60% of modern English words come from Latin or French. That&apos;s a big influence. Also, around 6% of English words come from Greek. And there are many words from other languages too.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;另一个需要了解的英语重要事实是，其他语言对它的影响很大。那么，是哪些语言呢？嗯，例如，一些专家说，大约30%的英语单词来自拉丁语，大约30%的英语单词直接来自法语。这意味着几乎60%的现代英语单词来自拉丁语或法语。这是一个很大的影响。此外，大约6%的英语单词来自希腊语。而且还有很多其他语言的单词。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;But what language family does English belong to? English is a Germanic language. That means English is related to languages such as German, Dutch, and Swedish. However, English speakers can&apos;t understand these other languages. If I hear German or Dutch, I don&apos;t understand anything. English is related to these languages, but they&apos;re very different. For example, Americans who only speak English can usually understand much more Spanish than German. That seems strange because English and Spanish are not related, but English and German are related.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;但是英语属于哪个语言系？英语是一种日耳曼语系的语言。这意味着英语与德语、荷兰语和瑞典语等语言有关联。然而，说英语的人并不能理解这些其他语言。如果我听到德语或荷兰语，我什么都听不懂。英语与这些语言有关，但它们非常不同。例如，只说英语的美国人通常能理解更多的西班牙语而不是德语。这似乎很奇怪，因为英语和西班牙语没有关系，但英语和德语却有关系。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The reason why English speakers can understand many words from Spanish, French or Italian is because these languages have many cognates. Cognates are words that have the same origin. For example, in English, we have the word patience, and in Spanish, this word is basencia. These words look very similar because they&apos;re cognates. So if an English speaker hears the Spanish word &quot;paciencia&quot;, they can probably understand the meaning.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;英语使用者能够理解许多西班牙语、法语或意大利语的词汇，是因为这些语言有许多同源词。同源词是指有相同起源的词。例如，在英语中，我们有“耐心”这个词，在西班牙语中，这个词是“basencia”。这些词看起来非常相似，因为它们是同源词。所以如果一个英语使用者听到西班牙语单词“paciencia”，他们很可能能理解其含义。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, one last interesting thing about English is that it has many words. Some people say that English is the language with the most words. I think this is probably, true because English has taken many words from other languages, like I said before.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，关于英语最后一个有趣的事实是，它有很多词汇。有些人说英语是词汇量最多的语言。我认为这可能是真的，因为正如我之前所说，英语从其他语言中借用了很多词汇。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;All right, now I&apos;m gonna ask you some questions about the video to see if you understood. Write your answers in a comment down below.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，现在我要问你一些关于视频的问题，看看你是否理解了。把你的答案写在下面的评论中。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;No. 1, when did Old English appear?&lt;/p&gt;
&lt;p&gt;No. 2, what language family does English belong to?&lt;/p&gt;
&lt;p&gt;No. 3, what are cognits?&lt;/p&gt;
&lt;p&gt;Okay, before we go, remember to sign up for our $1 Listening Practice seminars in download our free Listening Time podcasts to practice your listening skills. And of course, subscribe to the channel, click on the bell and follow us on Instagram. I&apos;ll see you next time.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Social Media Vocabulary for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-social-media-vocabulary-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-social-media-vocabulary-a1-beginners/</guid><pubDate>Mon, 05 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=12&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak. Before we start, remember to subscribe to the channel, click on the bell, and follow us on Instagram.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家好，欢迎大家观点这个初级英语练习视频。你可以用这个视频练习英语听力和理解能力。在开始之前记得关注我。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So today I&apos;m gonna talk about social media. Nowadays, many people have social media apps on their phones and computers. Many people use social media to communicate with their friends and family. They also use social media for many other things. Let&apos;s talk about the different social media apps.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;今天我想聊聊社交APP。现在大家的手机或电脑上都有社交APP。很多人在APP上和家人朋友聊天。他们也在APP做其他事情。让我们聊聊不同的APP。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The most famous app is Facebook. Facebook is very popular all around the world. People all around the world use Facebook every day. They use Facebook on their computers and they use Facebook on their phones. I think more people use Facebook on their phones, not their computers. Facebook was invented in 2004, but it wasn&apos;t popular then. I started using Facebook in 2010. When did you start using Facebook?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;最出名的APP是Facebook，在全世界都很受欢迎。全世界的人每天都在使用Facebook,不管是手机端还是PC端。我认为大多数人是在手机端使用。Facebook 创办于2004年，但那时候还不流行。我是在2010年开始用的。你呢？你知道如何使用Facebook吗？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/452978229d01b22e3f49757797e92162.png&quot; alt=&quot;Expression_21@2x.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;So let&apos;s talk about what you can do on Facebook. First of all, you can use it to post text, pictures, and videos. When you post something, all your friends can see it. I don&apos;t post much on Facebook. You can also use Facebook to send messages. You can send messages to one person or to a group. You can also follow people and pages on Facebook. I follow some news pages, so I can see the news on Facebook. You can do many things on this app, but I don&apos;t really like Facebook.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;让我们好好聊聊你可以在Facebook上做些什么。首先，你可以用它发布文字、照片和视频。当你发布内容时你所有的朋友都可以看到。我不怎么发。你也可以把Facebook当微信用，你可以把消息发给某个人或某个群。你可以关注某个人或某个人的朋友圈。我关注了一些新闻主页，所以我可以在Facebook上看新闻。你可以在这个APP上做任何事情，但我不怎么喜欢 用。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, so now let&apos;s talk about Instagram. Instagram is the most popular app for young people. Use this app to post pictures and videos. If you like pictures, then you&apos;ll probably like Instagram. I don&apos;t like Facebook, but I do like Instagram. I like it because it&apos;s fun to look at photos on Instagram. You can follow other people to see their pictures.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，下面我们聊聊 Instagram。这个APP在年轻人中很流行。可以用它发布图片和视频。如果你喜欢看图片，你大概率会喜欢这个APP。我很喜欢Instagram，因为在这上面看图片很有趣。你可以关注别人，看他们的图片。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Some people like following celebrities and other famous people. I don&apos;t really like following celebrities. How about you? Do you follow any celebrities on Instagram? Another thing you can do on Instagram is post an Instagram story. You can post many photos and videos to your story. I don&apos;t usually post on Instagram, but I look at other people&apos;s posts. I think that Instagram is better than Facebook.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;一些人喜欢关注名人和网红，我不怎么喜欢。你呢？你有在Instagram上关注名人吗？你可以在Instargram上发布一个主页。你可以发布很多照片和视频在主页上。我通常不怎么发布内容，但我会去看别人发布的内容。我觉得Instargram比Facebook好。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, so another social media app that people use is Twitter. I don&apos;t have Twitter, so I don&apos;t really know how to use it. But I know that it&apos;s a very popular app all around the world. Many people use this app to follow the news. People post news stories on Twitter. I don&apos;t need a Twitter account because I can read the news on Facebook.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;另一个人们喜欢用的 APP 叫 X 。我没有 X 账号，所以我不知道怎么用。但我知道这是个在全世界都很流行的APP。很多人用这个APP浏览新闻。人们在X上发布新闻。我不需要X账号因为我可以在Facebook上看新闻。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Another app that young people use is Snapchat. I had Snapchat when I was younger, but now I don&apos;t. People use Snapchat to send pictures and short videos to each other. Then these pictures and videos disappear after you view them.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;另一人年轻人很喜欢的是 Snapchat. 我年轻的时候也用 Snapchat 但现在不用了。人们用 Snapchat 互相发送图片和短视频。这此图片和视频在你查询后会消失。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;There are many other social media apps, too. The world loves social media.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;还有很多其他类似的APP。这个世界喜欢社区媒体。&lt;/em&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Breakfast Vocabulary for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-breakfast-vocabulary-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-breakfast-vocabulary-a1-beginners/</guid><pubDate>Sun, 04 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=11&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家好，欢迎观看初级英语听力视频，你可以用这个视频练习英语听力和理解能力。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, today we&apos;re gonna talk about breakfast. This is my favorite meal of the day. So I&apos;m happy to talk about it.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，今天我想聊聊早餐，这是我一天中最喜欢的一餐。我很愿意聊这个话题。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;First, let&apos;s talk about breakfast in the US. Many people think that Americans eat a big breakfast every day. You&apos;ve probably seen this in American movies and TV shows. You might see people eating eggs, bacon, sausage, pancakes and more.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;首先，让我们聊聊美国的早餐。很多人认为美国人每顿早餐都很丰盛。你大概是在美国电影和电视中看过。你可以看到人们在吃鸡蛋、培根、香肠和煎饼等。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;However, most Americans don&apos;t eat a really big breakfast on weekdays. Many people don&apos;t have time to cook a big breakfast before they go to work.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;然而，大多数美国人工作日的早餐不怎么丰盛。很多人工作日的早上没有那么多的时间做早饭。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Actually, it&apos;s really common for people to just eat cereal. I did this a lot when I was a kid. But on weekends, people have more time to enjoy their breakfast in the morning. So people might eat the type of breakfast that you see in the movies.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;其实，早上只吃麦片是很常见的，我小时候就这样。但在周末，人们有更多的时候享用早餐。所以他们会吃得很好，就像电影里一样。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I remember when I was a kid, my mom cooked more creative breakfasts on Saturdays and Sundays. My favorite breakfast that my mom cooked was crepes. I still remember how amazing they tasted.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我记得我小时候我妈会在周末做很有新意的早餐。我最喜欢的早餐是我妈做的可丽饼，至今难忘。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It&apos;s also common for Americans to go out for breakfast on weekends. Breakfast restaurants are really crowded on Saturday and Sunday mornings. And we also love enjoying a nice breakfast when we&apos;re on vacation. Basically, when we have the time, we love to eat a good breakfast.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;周末去外面吃早餐在美国也很常见。周末的早餐店人超多。我们也很享受假期的丰盛早餐。事实上，只要有时间，我们都愿意享受一顿美味的早餐。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In many other countries, people don&apos;t eat a lot for breakfast. I remember when I was in Europe, I saw many people having only a little sweet bread and coffee for breakfast. This definitely isn&apos;t enough for me, but for other people, this is enough. I think that in many countries, breakfast isn&apos;t an important meal. Lunch and dinner are usually more important.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;在其他国家，人们吃的早餐也很简单。我记得在欧洲时，我看到人们就吃一些甜面包和咖啡当早餐。这对我来说肯定不够，但对有些人来说足够了。我觉得在有些国家，早餐不是很重要。午餐和晚餐才重要。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In the US, some people say that breakfast is the most important meal of the day. What do you think? What&apos;s the most important meal of the day for you?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;在美国，很多人说早餐很重要，你觉得呢？你觉得哪顿饭比较重要？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now, let me describe my typical breakfast. Normally on weekdays, I eat eggs, bacon and fruit. I love the combination of bacon and eggs. They go together perfectly. I don&apos;t get tired of this food, even if I eat it every day. Of course, I always buy fresh and organic eggs, bacon and fruit. This is really important for me. And on weekends, I often go to restaurants to eat breakfast.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;现在，我来说说我的早餐。通常，工作日我会吃一些鸡蛋、培根和水果。我喜欢培根和鸡蛋的组合，这个组合很棒。即使我每天吃都不厌倦。当然，我总是买新鲜的有机鸡蛋、培根和水果。这对我很重要。周末我经常去早餐店吃饭。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I love going out to eat breakfast. There are a lot of amazing breakfast restaurants where I live. So I have many options. I usually eat different breakfast foods at restaurants.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我喜欢出去吃早饭。我住的地方有很多很棒的早餐店，所以我有很多选择。我经常在早餐店吃不同的食物。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One of my favorite breakfasts is a Mexican dish called Chile kilis. I order this food all the time. And I also really like sweet breakfast foods like French toast, pancakes and sweet bread. As you can see, I love breakfast in general.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我最喜欢吃的早餐之一是一种叫做“智利基利斯”的墨西哥菜。我经常点这个食物。我也很喜欢甜食早餐，比如法式吐司、煎饼和甜面包。正如你所见，我很喜欢早餐。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One other thing that I sometimes have for breakfast is coffee. I don&apos;t drink coffee every day, and I don&apos;t really like caffeine, but I really like warm drinks. So I often order coffee or hot chocolate when I eat breakfast at restaurants.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我早餐有时会喝咖啡。我并不是每天都喝咖啡，我也不太喜欢咖啡因，但我真的很喜欢热饮。所以我在餐馆吃早餐时，经常点咖啡或热巧克力。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I know some people that need coffee in the morning. If they don&apos;t have coffee, then they can&apos;t start their day. I&apos;m not like this. I sometimes have coffee with my breakfast, but it&apos;s not necessary.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我知道有些人早上需要喝咖啡。如果他们不喝，他们就不能开始他们的一天。我不像这样。我有时早餐时喝咖啡，但这不是必须的。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Leave a comment down below and tell me what you eat for breakfast. Remember to download my free Listening Time podcast and become a member at patreon.com slash listening time to receive my specialized training, which will help you understand native speakers. And if you wanna reach an advanced level of listening, then become a listening time family member. So you can train your listening with my advanced podcast episodes. Also, subscribe to the channel, click on the bell and follow us on Instagram. I&apos;ll see you next time.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Transportation Vocabulary for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-transportation-vocabulary-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-transportation-vocabulary-a1-beginners/</guid><pubDate>Sat, 03 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=10&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey, everybody! Welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak. Before we start, remember to subscribe to the channel, click on the bell, and follow us on Instagram.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家好，欢迎观看初级英语听力视频，你可以用这个视频练习英语听力和理解能力。在此之前，点赞、关注、评论一键三连。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You ready? So today, I&apos;m gonna talk about transportation. This is an important topic because we all use some kind of transportation in our lives. Let&apos;s talk about the different types of transportation.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;准备好了吗？今天我想聊聊交通工具。这是个很重要的话题，因为我们都要使用交通工具。让我们聊聊各种不同的交通工具。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One popular type of transportation is the subway. In other countries, people also use the words &quot;metro&quot; or &quot;underground.&quot; But in the US, we usually say &quot;subway.&quot; Many big cities around the world have a subway system.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;一种流行的交通工具是地铁。有些国家人们也用 “metro” 和 &quot;underground&quot; 称呼地铁，但在美国，我们通常用 “subway”。世界上很多大城市都有地铁。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In cities like Paris, London, and Tokyo, the subway system is amazing. The subways in these cities are very organized and efficient. However, many big cities in the US don&apos;t have good subway systems. Most people in the US drive cars, so they don&apos;t need to take the subway. In my hometown of San Diego, we don&apos;t have a subway system.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;巴黎、伦敦和东京都有很惊人的地铁系统。这些城市的地铁非常有条理和高效。然而，美国的许多大城市都没有良好的地铁系统。在美国，大多数人都开车，所以他们不需要坐地铁。在我的家乡圣地亚哥，我们没有地铁系统。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I like taking the subway in other countries because it&apos;s easy. You can go anywhere in the city without a car. But in some cities, the subway stations are dirty and a little scary. You need to be careful when you take the subway.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我喜欢在其他国家乘坐地铁，因为它很容易。你可以不开车去城市的任何地方。但有些城市，地铁站很脏，有点吓人。乘坐地铁时需要小心。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, another form of public transportation is taking the bus. Big cities have bus systems that help people move around. In some cities, buses are nice, clean, and safe. But in other cities, buses are old, dirty, and a little dangerous.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;另一种形式的公共交通是坐公交。大城市有公交系统，可以方便人们四处走劫。有些城市，公交车很舒适、干净、安全，但有些城市的公交车老旧、脏乱、还不安全。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For example, in Mexico, most buses are old and uncomfortable. They can also be dangerous because many bus drivers drive really badly. They drive really fast, and they often have accidents. Most people don&apos;t like taking the bus, but sometimes they have to. In many cities, taking the bus is cheap. If you don&apos;t have a lot of money, the bus can be a good option.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;比如，墨西哥，大多数公交车很老旧也很不舒适。它们也可能很危险，因为司机开得很快，而且经常发生事故。大多数人不喜欢坐公交车，但有时他们没有办法，在很多城市，公交车很便宜，如果你没什么钱，坐公交车是个不错误的选择。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, now let&apos;s talk about taxis and Ubers. In the past, many people took taxis, but nowadays, many people use Uber. I love using Uber. I use it all the time. An Uber is cheaper than a taxi and it&apos;s usually safe. I always have good experiences using Uber. I&apos;ve taken a few taxis before, but I didn&apos;t like it. Taxis are usually expensive. In some cities, Uber is illegal, so people can&apos;t use it. How about you? Do you use Uber in your city?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，现在我们聊聊出租车和网约车。以前很多人打车，但现在大家都用网约车。我喜欢用网约车,经常用。网约车比出租便宜还安全。网约车的体验总是很好。我偶尔也打车，但不喜欢，出租车比较贵。有些城市网约车不合法，所以人们没办法用。你呢，你会用网约车吗？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, another common type of transportation is riding a bike. This is a great way to move around the city because it&apos;s free. Riding bikes is also a healthy activity. The problem is that it&apos;s dangerous. In some cities, the drivers are crazy. So it&apos;s dangerous to ride a bike in the street. In other cities, there are bike lanes in the street, so it&apos;s safer. But I think it&apos;s always a little dangerous to ride a bike in the city.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;另一个公共交通是骑自行车。这是很好的出行方式，因为不需要花钱。骑行对身体也有好处。问题是有点危险，有些城市的司机很疯狂，所以在街道上骑行有点危险。有些城市有专门的骑行车道所以很安全。但我总觉得有点危险。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One more type of transportation is walking. This is my favorite type of transportation because it&apos;s easy, free, and fun. I love walking because I love being outside. I think everyone should try to walk more.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;另一种交通工具是步行。这是我最喜欢的方式因为简单免费还有趣。我喜欢步行，因为我喜欢外面。我觉得每个人都应该多走路。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;All right, that&apos;s all for today. Leave a comment and tell me what type of transportation you prefer. And remember to subscribe to the channel, click on the bell, and follow us on Instagram for more English tips and lessons. I&apos;ll see you next time.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Job and Work Vocabulary for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-job-work-vocabulary-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-job-work-vocabulary-a1-beginners/</guid><pubDate>Fri, 02 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=9&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak. Before we start, remember to subscribe to the channel, click on the bell, and follow us on Instagram.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家好，欢迎观点初级英语听力视频。你可以用这个视频练习英语听力和理解能力。在开始之前，记得点赞、关注、评论一键三连。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You ready? So today I&apos;m gonna talk about jobs. This is a really common topic because most adults have a job or some type of work. Let&apos;s talk about the different types of jobs that people have.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;准备好了吗，今天我想聊聊工作。这是一个很普遍的话题，因为每个成年人都有某种类型的工作。让我们聊聊人们不同类型的工作。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One common type of job is a part-time job. A part-time job is a job where you work fewer hours. I had part-time jobs when I was younger. I worked part-time at a clothing store, at a restaurant, and at my university. Many students have part-time jobs. They study in the morning and work in the evening. I did this when I was a student.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;有一种普遍的工作叫兼职，工作时间比较少。我年轻的时候在服装店、餐厅和大学做过兼职。很多学生都做过兼职，他们白天学习，晚上工作。我学生时期没有做过。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In the US. Many teenagers get a job when they&apos;re in high school. I got my first job when I was 17. I was in my last year of high school. I worked at a clothing store called Hollister. I didn&apos;t like that job, but I liked earning money.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;在美国，很多青少年高中时就找到了工作。我17岁时有了第一份工作。我高中最后一年在一家叫 Hollister 的服装店工作。我不是很喜欢那份工作，但我喜欢赚钱。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Some of my classmates worked at fast-food restaurants like McDonald&apos;s. I also had a part-time job when I was in college. I worked at the university&apos;s dining hall. A dining hall is the place on a university campus where students eat. I worked as a cook and a dishwasher at my dining hall. I didn&apos;t like washing dishes. I liked cooking more than dishwashing. How about you? Have you ever had a part-time job?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我有一些同学在类似麦当劳的快餐店工作，我大学时期也做过。我在大学食堂工作过，就是学生吃饭的地方。我负责做饭和洗碗。我不喜欢洗碗，我比较喜欢做饭。你呢？你做过兼职吗？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, now let&apos;s talk about full-time jobs. In the US, people who have full-time jobs usually work 40 hours a week or more. Some people work a lot more, like 50 or 60 hours a week. For some full-time jobs, you need a college degree. For other full-time jobs, you don&apos;t need a degree.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;现在，我们聊聊全职工作。在美国，人们每周全职工作40多个小时，有些人还要多一点，50或60个小时每周。有些工作需要大学文凭，有些不需要。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In the US, there are many different jobs available in different industries. Some examples of industries are finance, marketing, medicine, IT, and education. I work in the education industry because I&apos;m a teacher.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;在美国，不同行业有不同的工作机会。比如：金融、营销、医药、IT 和教育。我在教育行业工作，因为我是老师。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;There are many good jobs in the US for people who don&apos;t have degrees. For example, you can be an electrician, a plumber, a truck driver, or many other things. People who have these jobs make good money in the US. Most salaries in America are high compared to other countries. Americans make a lot of money, but they have to spend a lot of money. Life is very expensive in the US.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;在美国还有很多不需要文凭的工作。例如，您可以是电工、水管工、卡车司机或许多其工作。拥有这些工作的人在美国赚了很多钱。与其他国家相比，美国的大多数薪水都很高。美国人赚了很多钱，但他们必须花很多钱。在美国，生活非常昂贵。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The normal schedule for full-time jobs is from 9 am to 5 pm in the US. However, some people start work earlier, like at 8 am, and other people end later, like at 6 pm. I start work pretty early at 7:00 am, but I also finish early at 4:30 pm. I prefer starting work early and finishing work early. Most people work Monday to Friday, and they have weekends off. Most people don&apos;t like working on the weekends. I work in the morning on Saturdays, but I have Sundays off. I never work on Sundays. How about you? What&apos;s your work schedule?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;在美国，全职工作的正常时间表是从上午 9 点到下午 5 点。但是，有些人开始工作得更早，比如早上 8 点，而另一些人下班时间晚，比如下午 6 点。我早上 7：00 就开始工作，但我也会在下午 4：30 早早下班。我更喜欢早点开始工作，早点结束工作。大多数人周一至周五工作，周末休息。大多数人不喜欢在周末工作。我周六早上工作，但周日休息。我星期天从不工作。你怎幺样？你的工作日程是怎样的？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Alright, that&apos;s all for today. Leave a comment and tell me about your job. And remember to subscribe to the channel, click on the bell, and follow us on Instagram for more English tips and lessons. I&apos;ll see you next time.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Home and Housing Vocabulary for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-home-housing-vocabulary-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-home-housing-vocabulary-a1-beginners/</guid><pubDate>Thu, 01 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=8&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak. Before we start, remember to subscribe to the channel, click on the bell, and follow us on Instagram.&lt;/p&gt;
&lt;p&gt;大家好，欢迎观看初级英语听力视频。你可以用这个视频练习英语听力和理解能力。在正式开始之前，别忘了点赞、关注、评论一键三连。&lt;/p&gt;
&lt;p&gt;You ready? So today I&apos;m gonna talk about homes. This is an important topic because we talk about our homes a lot. Let&apos;s talk about the different types of homes.&lt;/p&gt;
&lt;p&gt;准备好了吗？今天我想聊聊房子。这是个很重要的话题，因为我们经常聊关于房子的话题。我们来聊聊不同的房子。&lt;/p&gt;
&lt;p&gt;Some people live in houses. Some people live in apartments, and other people live in other types of homes. Houses and apartments are the most common types of homes.&lt;/p&gt;
&lt;p&gt;有些人住独栋的房子，有些人住公寓，还有些人住其他类型的房子。独栋房子（小别墅）和公寓是最常见的住宅。&lt;/p&gt;
&lt;p&gt;In big cities, people often live in apartments. Apartments are very common in big cities. They&apos;re usually smaller and cheaper than houses. Some apartments are in really tall buildings. These buildings can have 20 or 30 floors sometimes. I don&apos;t wanna live on the 30th floor. I prefer living on the first or second floor. If you live outside the city, you probably live in a house, not an apartment.&lt;/p&gt;
&lt;p&gt;在大城市，人们经常住公寓。公寓在大城市里很常见。它通常比独栋的房子小一点，便宜一点。有些公寓造得巨高，有时候有20层或30层高。我不喜欢住在30层高的房子里。我喜欢住1楼或2楼。如果你生活在主郊区，你大概率住在独栋的房子里。&lt;/p&gt;
&lt;p&gt;People that live in the countryside usually live in houses. These houses are usually bigger than apartments. They also have backyards. A backyard is the place behind your house where you can have grass, trees, gardens, or a pool. When I was a kid, I loved playing in my backyard. It was fun to play outside every day. Most departments don&apos;t have backyards. They usually have balconies instead.&lt;/p&gt;
&lt;p&gt;生活在乡下的人通常住在独栋房子里。这些房子通常比公寓大很多，这些房子有一个后院。你可以在后院种草、种树、种花或挖个泳池什么的。我小时候很喜欢在后院玩，每天都玩得很开心。大多数公寓没有后院，但通常会有阳台。&lt;/p&gt;
&lt;p&gt;Okay, now let&apos;s talk about the price of houses and apartments in the US. Houses and apartments can be really expensive if you live in a big city. In my home state of California, houses and apartments cost a lot of money. The average price of a house in California is almost $600,000. Crazy. It&apos;s also really expensive to rent an apartment in California.&lt;/p&gt;
&lt;p&gt;接下来，我们聊聊美国各种房子的价格。如果你生活在大城市，独栋房子和公寓都贵得要死。我的家乡加利福尼亚州，独栋房子和公寓要花费很多钱。独栋房子平均600000美元。要死了！租房子是贵得要死，简直没法活。&lt;/p&gt;
&lt;p&gt;In the US, people usually rent apartments, but in some other countries, people often buy apartments. When I was younger, I shared an apartment with other roommates. It&apos;s common to have roommates in the US. Sometimes you have good roommates and sometimes you have bad roommates. Have you ever had roommates before?&lt;/p&gt;
&lt;p&gt;在美国，人们通常租公寓，但在别的国家，人们经常买公寓。我年轻的时候和别人合租一套公寓，在美国合租很常见。有时候会遇到好的室友，有时会遇到烂室友。你有合租过吗？&lt;/p&gt;
&lt;p&gt;Okay, now let&apos;s talk about other types of homes. Some people live in condos, which are similar to apartments. Single condos are part of a bigger building or complex, just like apartments. But in the US, many people buy condos, but they don&apos;t buy apartments.&lt;/p&gt;
&lt;p&gt;现在我们聊聊其他类型的房子。有些人生活在商品房中，这种房子和公寓有点像。单人公寓是大型建筑或综合体的一部分，就像公寓一样。在美国，很多人买商品房，不买公寓。&lt;/p&gt;
&lt;p&gt;One more type of home that exists in the US is the townhouse. Townhouses are similar to normal houses, but they&apos;re often smaller and cheaper. Also, they&apos;re usually part of a community of townhouses.&lt;/p&gt;
&lt;p&gt;美国还有一些类型的房子叫 Townhouse （类似联排别墅）。Townhouse 和独栋房子类似，但相对便宜点，小一点。此外，它们通常是联排别墅社区的一部分。&lt;/p&gt;
&lt;p&gt;So there are several different types of homes that people can buy or rent. Some people prefer houses, some people prefer apartments, and other people prefer condos or townhouses. I think I prefer houses. I hope I can buy a house in the future.&lt;/p&gt;
&lt;p&gt;因此，人们可以购买或租用几种不同类型的房屋。不同人喜欢不同类型的房子。我更喜欢独栋房子，希望有生之年能买一个。&lt;/p&gt;
&lt;p&gt;Alright, that&apos;s all for today. Leave a comment and tell me what type of home you live in. And remember to subscribe to the channel, click on the bell, and follow us on Instagram for more English tips and lessons. I&apos;ll see you next time.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Exercise Vocabulary for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-exercise-vocabulary-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-exercise-vocabulary-a1-beginners/</guid><pubDate>Wed, 30 Jun 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=7&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak. Before we start, remember to subscribe to the channel, click on the bell, and follow us on Instagram.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家好，欢迎观看初级英语听力视频。你可以用这个视频练习英语听力和理解能力。在开始之前，记得点选、关注、一键三连。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You ready? So today I&apos;m gonna talk about exercise. This is an important topic because everybody should exercise. Exercising or working out is necessary for good health. Let&apos;s talk about some different types of exercise.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;准备好了吗？今天我想聊聊锻炼身体。这是个很重要的话题，因为每个人都应该保持锻炼。保持锻炼是健康的必要条件。让我们聊聊不同的锻炼方式。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One popular type of exercise is running. I&apos;m a terrible runner because I get really tired when I run, but I wanna improve my running. Some people like running short distances, and some people like running long distances. I&apos;m pretty fast when I run short distances, but I&apos;m slow when I run long distances. I need to train more.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;一种流行的锻炼方式是跑步。我不擅长跑步因为我一跑就喘，但我想多练习跑步。有些人喜欢短路，有些人喜欢长跑。跑步我可以跑得很快，但长跑我跑不了多快。我得多练习。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Some people prefer running outside and other people run on the treadmill. A treadmill is a machine for running. I don&apos;t like running on the treadmill. I prefer running outside in nature. How about you? Do you prefer running outside or on the treadmill?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;有些人喜欢户外跑，有些人喜欢在跑步机上跑。我不喜欢在跑步机上跑。我喜欢在自然环境中跑。你呢？你喜欢在哪里跑步？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, another popular type of exercise is weightlifting. People lift weights to build muscle and get stronger. Most people go to the gym to lift weights. In the past, I went to the gym often to work out. I lifted weights every week at the gym. But now I don&apos;t go to the gym. I have some weights at home, so I can lift weights here, but I don&apos;t have a lot of equipment, so I can&apos;t do many exercises. Some people have their own mini gym in their garage.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;另一个流行的锻炼方式是举重。人们通过举重锻炼肌肉，让自己变得强壮。有些人去健身房锻炼。以前，我会在结束工作后去健身房，我每周会去健身房练习举重，但现在不去了。我家里有几个举重器械，所以我可以在家里锻炼，但我器械不多，所以只能做一些简单的锻炼。有些人家里车库有个简易的健身房。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Weightlifting is hard because weights are heavy. If you&apos;re not strong, you can&apos;t lift a lot of weight. But if you start lifting weights, you can get stronger.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;举重很难因为杠铃很重。如果你不够强壮，你举不了多重，但如果你开始练习，你就会变得强壮。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Alright, another popular type of exercise is playing sports. Playing sports is good exercise and it&apos;s fun. Some people don&apos;t need to run or lift weights because they already play sports. Playing sports is good for your health. When I was young, I played many sports. I was pretty healthy. Sometimes I played sports with my friends and other times I played by myself. What&apos;s your favorite sport?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;另一种流行的锻炼方式是玩竞技运动。竞技运动是很好的锻炼方式，同时还很好玩。有些人不需要刻意地锻炼，因为他们已经有足够的竞技运动。这样的运动对你的健康有益。我年轻时参与过很多运动，那时候我的身体很健康。有时候我和朋友们一起，有时候我自己玩。你最喜欢的运动是什么？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Another popular type of exercise is hiking. This is one of my favorite activities. Hiking is a great way to exercise, because you don&apos;t need any equipment. It&apos;s free. Also, you can enjoy nature when you hike. If you live in a rural area, you probably have many places to hike. If you live in a big city, it&apos;s harder to find places to hike. I love hiking in the mountains, the forests, the deserts, and in the hills.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;另一个流行的运动是徒步。这是我喜欢的运动之一。徒步是运动的好方法，因为你不需要任何器械，很简单。在徒步的过程中你可以亲近大自然。如果你住在乡下，你可能有很多适合徒步的地方。如果你住在大城市，可能很难找到适合徒步的地方。我喜欢在山涧、森林、荒漠徒步。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In the US, hiking is a very popular activity. People go hiking with their friends and sometimes with their dogs. In other countries, hiking isn&apos;t so popular. When I have the chance, I try to find new places to go hiking.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;在美国，徒步是很流行的运动项目。他们要么和朋友，要么和自己的宠物狗一起徒步。有些国家并不怎么流行徒步。如果有机会，我会尝试寻找新的徒步点。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, one more type of exercise is walking. This is the simplest form of exercise. You can walk anywhere. I try to walk every day if I can, because I really like walking. So overall, there are many different types of exercise. You should try to exercise every day if you can.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;还有一个运动方式是步行。这个很简单。你可以在任何地方步行。我尝试每天保持步行，因为我真的很喜欢步行。总的来说，有很多不同的运动方式。你应该尝试每天保持运动。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Alright, that&apos;s all for today. Leave a comment and tell me which type of exercise you like best. And remember to subscribe to the channel, click on the bell, and follow us on Instagram for more English tips and lessons. I&apos;ll see you next time.&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Daily Routine Vocabulary for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-daily-routine-vocabulary-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-daily-routine-vocabulary-a1-beginners/</guid><pubDate>Tue, 29 Jun 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=6&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak. You ready?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家好，欢迎观看初练英语听力练习视频。你可以用这个视频练习英语听力和理解能力。准备好了吗？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So today I&apos;m going to talk about my daily routine. My routine is different on weekdays and weekends. I&apos;ll tell you about my routine on weekdays.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;今天，我想聊聊我的日常生活。工作日和休息日有所不同。我会告诉你我在工作日的日常。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So I normally wake up at about 6 or 6:00 am. I like waking up early. I don&apos;t like getting up late. When I wake up, the first thing I do is read my Bible. Then I study languages for a little while. Currently, I&apos;m studying Indonesian. I like to study in the morning because I feel motivated. Other people prefer studying in the evening. Do you like studying in the morning, afternoon, or evening?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我通常6点或6点半起床。我喜欢早起，不喜欢睡懒觉。醒来第一件事先读圣经，然后学一会语言。目前，我正在学习印度尼西亚语。我喜欢早上学习，因为我感觉早上更有动力，有些人喜欢晚上学习。你呢？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So after I study, I usually eat some fruit. This is my first food of the day. Then I start my work. I usually start working at 7:30 am. Most other people start at 8 am or 9 am. I like starting early though.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;在我学习之前，我通常会吃一些水果。这是我每天吃的第一种食物。然后就开始工作。我通常早上7点半开始工作。大多数人8点或9点开始工作。不过，我喜欢早一点。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I&apos;m an English teacher and I teach many students. I have different students every day. Some days I have many classes and other days I have fewer classes. Most of my students are from Brazil and Russia, but I have students from many other countries too. Every day I talk to people from all over the world. This is really fun. I love my job.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我是一个英语，老师，有很多学生。每天都有不同的学生。有些时候课很多，有时少一点，大多数学生来自巴西和俄罗斯，但也有来自其他国家的。我每天和来自不同国家的人聊天。这很有意思。我热爱我的工作。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So during my workday, I have some breaks. Sometimes I have a 30-minute break between classes. During my breaks, I eat, study, and hang out with my wife. My last class usually ends at 4:30 or 5:00 pm. Many Americans get off work at 5:00 pm.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;在工作期间我有一些休息时间。有时候在课间有半个小时的休息。在休息时间，我会吃点东西，学习或和老婆出去溜达溜达。我最后一节课在4点半或5点结束。大多数美国人5点下班。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;After I get off work, I eat dinner. My wife cooks dinner every weekday, so we eat at home. I&apos;m always hungry when I finish work. In the US, people eat dinner early, like at 6:00 pm. This is very common. In other countries, people eat dinner late, like at 9:00 pm. I don&apos;t like this. For us, dinner is the biggest meal of the day. We eat a lot for dinner. My wife and I eat meat, vegetables, and other food.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我下班后就吃晚饭。我老婆每个工作日都会做饭，所以我们在家吃。每次结束工作我都饿得要死。在美国，人们差不多6点吃晚饭。这很普遍。在其他国家，人们晚饭吃得晚，差不多9点。我不喜欢这么晚吃饭。对我们来说，晚餐是一天中最重要的一顿饭。我和我老婆吃了肉，蔬菜和一些其他食物。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Some days I exercise in the evening, too. I don&apos;t exercise every day, only some days. I should exercise more, though. After I exercise and eat dinner, I eat dessert. I normally have milk and cookies. I love milk and cookies. After dessert, I study my languages more. Then I spend time with my wife. Lastly, I take a shower, brush my teeth, and get ready for bed. I usually go to bed at 10:00 pm. So that&apos;s my normal routine on weekdays.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;有些日子我也会在晚上锻炼。我不是每天都锻炼，只有几天。不过，我应该多运动。运动和吃晚饭后，我吃甜点。我通常吃牛奶和饼干。我喜欢牛奶和饼干。吃完甜点后，我更多地学习我的语言。然后我花时间和我的妻子在一起。最后，我洗个澡，刷牙，准备睡觉。我通常在晚上 10：00 上床睡觉。这就是我平日的例行公事。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I like to have a consistent routine. I plan my days, and I try to follow my plan. Some people don&apos;t like planning their days. They prefer to do different things every day. I like doing different things too, but I like having a general plan to follow. If I don&apos;t have a general plan, I feel lost.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我喜欢日常生活保持一致。我计划我的日常并尝试按计划执行。人们不怎么喜欢计划自己的日常生活，他们喜欢体验每天不同的生活，我也喜欢体验不同的生活，但喜欢有一个大致的计划去执行。如果我没有做计划，我会感觉不自在。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I like having a daily routine. However, on the weekends, I do many different activities. My weekends are very different from my weekdays, but I always wake up and go to bed at the same time every day. That doesn&apos;t change. I like to start and end every day at the same time.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;工作日我喜欢按计划工作，但周末我喜欢体验不同的事件。我周末的生活和工作日很不同。但我总是按时起床和睡觉，这不会改变。我喜欢有规律的生活。&lt;/em&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: New Year&apos;s Resolutions Vocabulary for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-new-years-resolutions-vocabulary-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-new-years-resolutions-vocabulary-a1-beginners/</guid><pubDate>Mon, 28 Jun 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=5&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak. You ready?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家好，欢迎观看初级英语听力视频。你可以用这个视频练习英语听力和理解能力。准备好了吗？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So today, I&apos;m going to talk about New Year&apos;s resolutions. What is a New Year&apos;s resolution? This is a goal or an objective that you have for the next year. When it&apos;s the end of the year; some people make New Year&apos;s resolutions. They want to have a good year and do many things. Let&apos;s talk about some common resolutions.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;今天我想聊聊新年目标。什么是新目标？就是计划下一年的目标或项目。年底时，很多人会定新年目标。他们希望度过美好的一年，希望能做很多事情。让我们聊聊一些常见的新年目标。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One common New Year&apos;s resolution is to lose weight. Many people plan to lose weight during the New Year. This is a good resolution. It can help you be healthy. It&apos;s not easy to lose weight, though. It can be difficult. You need to eat healthy food, and you need to exercise. Many people go to the gym in January because their New Year&apos;s resolution is to lose weight. But not everyone reaches their goal. Many people quit.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;其中一个常见的新年目标就是减肥。很多人计划在新的一年中减肥成功。这是个好目标，它可以让人更健康，尽管这很不容易。你喜欢吃得更健康，保持运动。很多人在一月份选择去健身房，因为他们决定减肥。但不是每个人都能实现，很多人中途放弃了。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, another common New Year&apos;s resolution is to study English more. This is a good New Year&apos;s resolution. Some people want to learn English to help their career. If you speak English, you can have better opportunities. For some jobs, you need to speak English. And for other jobs, you need to read and write in English. English is important for many jobs. Maybe English will help your career too. This year, my goal is also to study more languages.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;另一个常见的新年目标是学英语。这是个好目标。很多人想通过学习英语来提高职业竞争力。如果你会英语，那你就有更多的机会。有些工作需要说英语，有些需要能看懂或能用英语写作。对很多人来说英语很重要。也许英语会对你的职业生涯有帮助。今年我的目标是学习更多语言&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Alright, another common New Year&apos;s resolution is to read more books. Some people are very busy, so they don&apos;t read a lot. Other people are not good at reading, but they want to improve. And some people don&apos;t like reading, but they need to read. Many people have the New Year&apos;s resolution to read more. I think that&apos;s good. I want to read more, too. I want to read many books this year. How many books do you want to read this year? Maybe you can read books in English this year. That&apos;s a good resolution.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;另一个常见的新年目标是读书。有些人很忙没时间读书。有些人不擅长阅读，但想通过阅读提升自己。还有些人不需要阅读，但他们需要阅读。很多人的新年目标是多读书。我认为这很好，我也想多读点书。你新年打算读多少书？也许你今年可以选择阅读英语书。这是个好目标。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, another common New Year&apos;s resolution is to learn a new activity. This is a fun one. There are many activities that you can learn. Some people learn a new sport. Other people learn a skill. It&apos;s good to learn new things. Maybe you can take a class to learn something new. There are many classes that teach you different skills. You can look for classes in your city.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;另一个新年目标是学一门新的活动。这很有意思。有很多技能可以学。有些人选择一项运动。另一些人选择学一项技能。学习新东西是好事。也许你可以去报个班学一些新东西。有很多课程教你学不同的东西。你可以在你所在的城市找找。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Another common New Year&apos;s resolution is to quit smoking. This is not a fun resolution, but it&apos;s good. I don&apos;t smoke, so I don&apos;t need to quit. But I could stop other bad habits. For example, I eat a lot of sugar. So maybe I should eat less sugar this year. Or maybe I should eat more vegetables.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;另一个新年目标是戒烟。这不是个有趣的目标，但很好。我不抽烟，所以不需要戒烟。但我可以戒掉其他的坏习惯。比如，我吃太多的糖。也许今年我该少吃点。或者我应该吃更多的可蔬菜。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;These are good resolutions. There are many different New Year&apos;s resolutions. I think this is good because people want to accomplish goals. It&apos;s good to accomplish goals. Okay, that&apos;s all for today. Leave a comment and tell me if you have a resolution for this year. I&apos;ll see you next time.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;这些都是很好的解决方案。有许多不同的新年决心。我认为这很好，因为人们想要实现目标。完成目标是件好事。好了，今天就到这里。发表评论并告诉我您今年是否有解决方案。下次再见。&lt;/em&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Pet Vocabulary for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-pet-vocabulary-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-pet-vocabulary-a1-beginners/</guid><pubDate>Sun, 27 Jun 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=4&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to practice your listening and comprehension as I speak. You ready?&lt;/p&gt;
&lt;p&gt;大家好，欢迎观看初级英语听力视频。你可以用这个视频练习听力和理解能力。&lt;/p&gt;
&lt;p&gt;So today I&apos;m going to talk about pets. This is a fun topic because many people have pets and like animals. Let&apos;s start with dogs, since dogs are the most common pets in the US, so many people have dogs. You can see and hear dogs everywhere.&lt;/p&gt;
&lt;p&gt;今天，我想聊聊宠物。这是一个有趣的话题，因为很多人都养宠物，也喜欢动物。我们从狗开始聊，因为在美国狗是最普遍的宠物。很多人养狗。你可以在任何地方看到狗或听到狗叫。&lt;/p&gt;
&lt;p&gt;When I was younger, my family had many dogs. Some of them were big and some of them were small. They were all different kinds of dogs. I always liked our big dogs more. They were smart and fun. Our small dogs were cute, but they weren&apos;t very smart.&lt;/p&gt;
&lt;p&gt;我还是小伙子的时候，我家里人养了很多狗，有些大有些小。它们是不同品种的狗。我比较喜欢大狗，它们更聪明有趣。我家体型小的狗虽然可爱，但有点蠢。&lt;/p&gt;
&lt;p&gt;All of our dogs loved to play. They wanted to play all day. I like dogs, but now I don&apos;t want to have dogs. If you have dogs, you need to spend a lot of time with them. They need a lot of attention. In the US, people treat their dogs very well. They give them a lot of attention and they play with them a lot.&lt;/p&gt;
&lt;p&gt;所有狗都喜欢玩，它们要玩一整天。我喜欢狗，但现在没有养。如果你养了狗，你得花很多时间在它们身上。它们需要你的关注。在美国，人们对他们的狗很好。他们很关注自己的狗还经常和它们玩。&lt;/p&gt;
&lt;p&gt;Okay, now let&apos;s talk about cats. Some people like cats more than dogs, but I don&apos;t like cats at all. Actually, I&apos;m allergic to cats, so I stay away from them. Many people like cats because they&apos;re independent. They don&apos;t need a lot of attention like dogs do. So if you have a cat, it&apos;s easy. Also, cats are funny animals. There are many videos of cats doing very funny things. My family never had cats, though. What about you? Do you prefer cats or dogs?&lt;/p&gt;
&lt;p&gt;现在，我们聊聊猫。一些人喜欢猫而不是狗，但我一点也不喜欢。其实，我对猫过敏，所以我会和它们保持距离。人们喜欢猫是因为它很独立。它们不需要你太关注它们，不像狗。所以，养猫比较容易。猫也是有趣的动物。猫有很多搞笑的视频。我家人从来没养过猫。你呢？你喜欢㺃还是猫？&lt;/p&gt;
&lt;p&gt;Now let&apos;s talk about other types of pets. In the US, some people like to have small pets like hamsters or Guinea pigs. These animals live in cages, so they&apos;re easy pets to have. You just need to feed them and clean their cage. I don&apos;t think these pets are very fun. They&apos;re a little boring in my opinion. But many people prefer these types of pets. I&apos;ve never had a hamster or Guinea pig before, but I ate a Guinea pig when I was in Peru. In some countries, Guinea pigs are food, not pets.&lt;/p&gt;
&lt;p&gt;现在，我们聊聊其他宠物。在美国，有些人喜欢养很小的宠物，比如，仓鼠和豚鼠。这些宠物可以在笼子里生活，所以养起来很容易。你只要喂养它们，清理它们的笼子就行。我不知道养这些宠物有什么意思。在我看来它们有些无趣。但很多人喜欢这类宠物。我从来没有养过仓鼠和豚鼠，但我在秘鲁吃过豚鼠，在一些国家，豚鼠是食物。&lt;/p&gt;
&lt;p&gt;Other types of pets include birds, bunny rabbits, fish, and reptiles. I had three fish when I was younger. Two of these fish died pretty fast, but one of the fish lived for several years. Fish are boring pets, though. When I was very young, my family had a gecko. I liked to watch this gecko eat. It ate live crickets and worms. That was a cool pet.&lt;/p&gt;
&lt;p&gt;其它宠物包括鸟、小兔子、鱼和爬行动物。我年轻的时候养过三条鱼，其中两条很快就死了，但有一条活了几年。养鱼也很无聊。我小时候，家里养过壁虎。我喜欢看它吃东西。它喜欢吃活的蟋蟀和虫子。那是很酷的宠物。&lt;/p&gt;
&lt;p&gt;In the US, there are many animal shelters. An animal shelter is a place that takes care of animals that don&apos;t have owners. Most of these animals are dogs. Of course, if you go to an animal shelter, you can adopt these animals if you want. My family adopted several dogs from these animal shelters. Some of these dogs were nice and fun and some of these dogs were not very nice.&lt;/p&gt;
&lt;p&gt;美国有很多动物收容所。动物收容所是照顾没有主人的动物的地方。大多数是狗。当然，如果你愿意，你可以在动物收容所领养动物。有些狗很可爱，有些不。&lt;/p&gt;
&lt;p&gt;My favorite pet was our first dog. She was very smart and she was beautiful. I played with her and I pet her every day. She lived with us for over 10 years. I miss that dog. If I get a pet in the future, it will be a dog, but I don&apos;t think I want a pet.&lt;/p&gt;
&lt;p&gt;我最喜欢的宠物是我家第一只狗。她又聪明又好看。我会抚摸她，和她玩。她和我们生活了10多年，我很相信她。如果未来我想养宠物，肯定会选狗，但我现在不想养。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Weather Vocabulary for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-weather-vocabulary-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-weather-vocabulary-a1-beginners/</guid><pubDate>Sat, 26 Jun 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=3&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to train your listening and comprehension as I speak. You ready?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家好啊，欢迎观看这个英语听力视频，你可以用这个视频练习英语听力和理解能力。准备好了吗？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So today I&apos;m going to talk about the weather. This is an important topic because everybody talks about the weather. If you are learning English, you need to know how to talk about the weather.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;那么，今天我想聊聊天气。这个主题很重要，因为每个人都会聊到天气。如果你想学好英语，那你需要知道如何用英语聊天气。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So let&apos;s start with sunny weather. Sunny weather is my favorite type of weather. When it&apos;s sunny outside, I&apos;m happy. For me, hot weather is better than cold weather. Some people don&apos;t like the heat, but I don&apos;t mind the heat. It can be uncomfortable, but for me, that&apos;s okay.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我们从晴天开始。我最喜欢晴天，每当外面天气晴朗，我就很开心。对我来说，热天比冷天好。很多人不喜欢天热，这会让人不舒服，但我无所屌谓。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Some places are too hot though. For example, the city of Las Vegas is really hot in the summer. I like hot weather, but not that hot. In really hot cities, you need to stay inside during the afternoon. In the US, most buildings in hot cities have air conditioning.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;有些地方特别的热。比如，拉斯维加斯的夏天。我是喜欢天气热一点，但不是那种热死人的天气。在那种巨热的城市，整个下午你都得待在室内。在美国，大多数建筑都有空调。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, now let&apos;s talk about cloudy days. I hate cloudy days when the sun is not shining, I feel a little sad because I love sunny days, but cloudy days are normal. Every city has cloudy days. Some cities are always cloudy, like London. I can&apos;t live in a cloudy city. I need sunshine. Do you like sunny or cloudy days more?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;让我们聊聊阴天。我讨厌看不到太阳的阴天，我会有点难受。但阴天也很正常，每个城市都会有阴天。有些城市老是阴天，比如伦敦。我没办法在老是阴天的城市生活。我需要阳光。你喜欢晴天还是阴天？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, now let&apos;s talk about rainy days. For me, rainy days are the worst. I love being outside. So this is why I don&apos;t like the rain. When it rains, I can&apos;t do anything outside. I have to stay indoors all day.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;现在我们聊聊雨天，对我来说，雨天是最糟糕的，因为我喜欢待在外面。只要一下雨，我在外面什么也做不了，只能傻乎乎地待在室内。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Some people really like the rain. My wife likes the rain, but only when she&apos;s inside. She says that the sound of the rain is calming. I don&apos;t agree. I don&apos;t like the sound of the rain. It reminds me that I can&apos;t go outside. Of course, you can go outside when it&apos;s raining, but you need to take an umbrella. If you don&apos;t have an umbrella, you get wet. Sometimes it starts raining when I&apos;m not home and I don&apos;t have an umbrella with me. This is the worst. I don&apos;t like getting wet.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;有些人喜欢雨天，我老婆就是，但仅限于她在室内。她说下雨的声音能让感受到平静。我不认同这样的说法。我不喜欢下雨的声音，这意味着我不能出门。当然，你可以出门，但你得带伞。如果不带会淋湿。有时候下雨我没有带伞，就很头疼。我不喜欢被雨淋湿。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Also, when it rains, it can be dangerous to drive. Many people have car accidents when it rains. When the streets are wet, you need to drive slower. If you don&apos;t, you can have an accident. On rainy days, there are a lot of car accidents. I don&apos;t like driving in the rain.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;同时，下雨会让开车变得危险。很多人发生车祸都是因为下雨。当街道变得很湿，你得开得很慢。如果你非要装逼，你可能会出车祸。雨天会有很多车祸，我不喜欢在雨天开车。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;All right, now let&apos;s talk about windy days. Some cities have a lot of wind and this can be good or bad. If you live in a hot city, the wind can be good because it cools the city down. But if you live in a cold city, the wind can be bad because it makes it even colder. If the wind is really strong, it can cause problems. Sometimes trees fall down because of the strong wind. Usually, I prefer days that aren&apos;t windy.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;好的，现在我们聊聊大风天。有些城市经常刮风，风也有好有坏。如果你生活在一个 很热的城市，有风是好的，因为可以降温。但如果你生活在很冷的城市，风可能不好，因为会更冷。如果风特别大，那就要出问题了。有些树倒了就是因为风太大。通常情况下，我喜欢没有风的天气。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, lastly, let&apos;s talk about the snow. It doesn&apos;t snow in my city, so I don&apos;t see the snow often. Some years, my family goes to the mountains in the winter to ski and snowboard. I like the snow, but I don&apos;t want to live in a snowy city. It&apos;s too cold and life is more difficult in the snow.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;最后，让我们聊聊下雪天。我们这里不下雪，所以我很少能看到雪。有些年，我们全家人冬天去山上滑雪。我喜欢下雪，但我不需要生活在雪很大的城市。在这样的城市生活很冷，也很难。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I have some students that live in really cold cities. During the winter, the temperature can be minus 20 or minus 30 degrees Celsius. For me, that&apos;s crazy. I don&apos;t like the cold.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我有一些学生生活在很冷的城市，冬天时他们那边温度会降到零下20-30度。那对我来说太疯狂了。我受不了太冷的天。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Another bad type of weather is stormy weather. In the US, we have some bad storms like hurricanes and tornadoes. I&apos;ve never seen a storm like this before, but I&apos;ve seen many thunderstorms. These storms are not that bad, but I don&apos;t like lightning. Lightning can be scary.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;另一个不好的天气是暴风雨，在美国，我们有一些严重的风暴，如飓风和龙卷风。我以前从未见过这样的风暴，但我见过很多雷暴。这些风暴还不错，但我不喜欢闪电。闪电有点吓人。&lt;/em&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Food Vocabulary and Culture for A1 Beginners</title><link>https://blog.ithuo.net/posts/learning-english-food-vocabulary-culture-a1-beginners/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/learning-english-food-vocabulary-culture-a1-beginners/</guid><pubDate>Fri, 25 Jun 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=2&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to train your listening and comprehension as I speak. You ready?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;兄弟们好，欢迎观看 A1 级别的英语听力视频。你可以用这个视频来练习英语听力和理解能力。准备好了吗？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So today I&apos;m going to talk about cooking. I do not know how to cook, so I do not know a lot about this topic. However, I like eating, so I like talking about food in general.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;今天，我想聊聊做饭。我不会做饭，我不太了解这个话题。不过，我是个吃货，所以我可以聊聊常见的食物。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I am lucky because my wife cooks very well. She has a natural talent for cooking. So she cooks well. That means that I eat well. Let me tell you about some of the things that my wife cooks.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我很幸运有一个会做饭的老婆。她很有做饭的天赋，这就意味着我吃得很好。我们聊聊我老婆做的一些食物。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Since she is Mexican, she likes cooking Mexican food. Sometimes she makes tacos, which are delicious. There are many types of tacos. So my wife can cook different tacos each time. I also cooked tacos in the past, but I don&apos;t cook well, so my tacos weren&apos;t very good. I cooked &quot;tacos de lengua&quot;, tongue tacos, but I didn&apos;t cook them very well. My wife cooks much better.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;她很喜欢做墨西哥菜，因为她是墨西哥人。有时候她会做 tacos ，好吃极了。tacos 有很多种类型，我老婆每次都会做不同的。我以前也做过，但做得不好。我做过一些名字奇奇怪怪的 tacos，但做得不好。我老婆做得好。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The only thing that I cook well is eggs. I love eggs and I eat them almost every morning. I think eggs are the best breakfast food. I usually eat scrambled eggs, but I also eat other types of eggs, too. My favorite type is eggs Benedict. This is my favorite breakfast. Have you tried eggs Benedict?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我唯一能做好的就是鸡蛋。我喜欢吃鸡蛋，每天早上都吃。我认为鸡蛋是最好的早餐。我喜欢吃炒鸡蛋，也喜欢吃其他类型的，最喜欢的是火腿鸡蛋饼。那是我最喜欢的早餐，你要不要试试？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So my wife also makes pasta. She makes really good pasta. She doesn&apos;t buy the pasta in the box that you buy from the store. She makes the pasta by hand. She makes the noodles and they taste so good. When you make pasta by hand, it tastes better. I love all types of pasta, but my favorite is ravioli. For me, ravioli is the perfect food. Actually, I like all Italian food. When we were in Italy, we ate some amazing food.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我老婆也会做意大利面，做得很好吃。她不从商店购买已经包装好的意大利面，她自己亲手做。她自己做的面好吃极了。你自己亲手做的面一定好吃。我喜欢各种意大利面，但最喜欢的是 ravioli。对我来说 ravioli 是最棒的食物，其实我喜欢所有意大利食物。我在意大利时吃了很多很棒的食物。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;My wife also cooks a lot of meat. We like eating different cuts of steak every week. We try to buy cheap meat because meat can be expensive. We don&apos;t want to spend a lot of money, so we buy cheap meat.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我老婆也做过很多肉，我们喜欢每周吃点不同的牛肉。我们尽量买便宜点的肉，因为肉很贵。我们不想花太多的钱，所以买便宜点的肉。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;My wife cooks the meat in a pan, which is easy. Other people cook their meat on a grill. We don&apos;t have a grill, so we use a pan. I think that meat tastes good if it&apos;s cooked on a pan or on a grill. Meat is always good. I hope my wife cooks meat tonight.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我老婆用平底锅做肉，这很方便，也有人用烤架。我们没有烤架，所以用平底锅。我觉得用烤架和平底锅做的肉都很好吃。肉总是好的，我希望我老婆今晚做做点肉吃。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;She also cooks really good breakfast. She makes really good pancakes. I like to eat pancakes with maple syrup and peanut butter. I know that&apos;s a little strange, but it&apos;s delicious. I love pancakes and peanut butter.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;她做早餐也是一绝。她煎的饼超好吃。我喜欢在煎饼上放枫糖浆和花生酱。我知道这听起来有点奇怪，但真的很好吃。我喜欢煎饼和花生酱。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;My wife also cooks chilaquiles, a common Mexican breakfast. This is my favorite breakfast in the world. I love chilaquiles. This dish has tortilla chips, salsa, cheese and cream. I like it with eggs on top. It&apos;s so good.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我老婆也会做 chilaquiles (一种煎饼)，一种常见的墨西哥早餐。这是我最喜欢的早餐（放屁，他上面说最喜欢的早餐是鸡蛋）。我喜欢吃 chilaquiles。这道菜有玉米片、莎莎酱、奶酪和奶油。我喜欢上面有鸡蛋，简直了都。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I don&apos;t know which is better, breakfast or dinner. In my family, we cook dinner five days a week. The other days we go out to eat dinner or we eat dinner with other people. Sometimes we eat dinner with my parents and other times we eat dinner with my sister. Tonight we will eat dinner with my parents and my mother will cook dinner. When I was a kid, my mother cooked dinner every weekday, every evening. We ate dinner at 6:30pm every day. Do you eat dinner at the same time every day?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我不知道早餐和晚餐哪个更好。在我们家，我们每周做五次晚饭。其他几天我们出去吃或和其他人一起吃。有时候和父母一起吃，有时候和姐妹一起吃。今晚我们和父母一起吃，我老娘亲自下厨。我小时候，我老娘每个工作日都自己做晚饭。我们一般每天六点半吃晚饭。你们呢？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In the US, it&apos;s common for families to eat dinner together. We sit together at the table, we eat and we talk about our day. Dinner time is important in the US. In other countries, people eat dinner late, like at 8pm or 9pm. But this is too late for me. I don&apos;t want to eat dinner late. I like eating dinner at 5, 6 or 7pm. This is a good time for dinner.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;在美国，一家人一起吃晚饭是很普遍的。我们围坐在桌子前，一起吃饭，一起聊今天过得怎么样。晚饭对于美国家庭来说很重要。有些国家，晚饭吃得很晚，可能8-9点。这对我来说太晚了。我不想吃得太晚。我喜欢5-6点左右吃。这是晚饭的最佳时间。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;What do you like eating for dinner? I like every type of food from every country. I can eat anything. And I love trying new foods. Like I said, I don&apos;t cook well, but I eat well. Maybe I will learn to cook in the future, but I don&apos;t know. I don&apos;t like cooking and I don&apos;t have the natural talent to cook. I prefer eating, not cooking. My wife cooks very well, so I don&apos;t need to learn. I&apos;m thankful for that.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;你晚饭喜欢吃什么？我什么都吃，不管哪个国家的食物。我喜欢尝试新的食物。就像我说的，我不会做，但我能吃啊。也许我该学做饭，但怎么说呢，我不喜欢做饭，我也没有做饭的天赋。我就好吃。我老婆擅长做饭，我不需要学，我太幸运了，感谢老婆和上帝。&lt;/em&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Learning English: Tips and Tricks for A1 Beginners</title><link>https://blog.ithuo.net/posts/english-comprehension-made-easy-begin/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/english-comprehension-made-easy-begin/</guid><pubDate>Thu, 24 Jun 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1Bx421Q7nU&amp;amp;p=1&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; muted=&quot;false&quot;  danmaku=&quot;false&quot;&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;Hey everybody, welcome to this A1 English listening practice video. You can use this video to train your listening and comprehension as I speak.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;大家好，欢迎观看这个 A1 级别的英语练习视频。你可以用这个视频练习你的听力和英语理解能力。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You ready? So today I&apos;m going to talk about language learning. If you&apos;re watching this video, you&apos;re probably learning English. So I hope this is an interesting topic for you.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;准备好了吗？今天我想聊聊关于如何学习第二语言。如果你正在看这个视频，你大概是在学习英语。那么，我希望这是一个你感兴趣的话题。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Language learning is hard, and if you learn a language, you need to spend a lot of time studying. This is the most important part of learning a language: time. If you don&apos;t spend a lot of time studying, you won&apos;t learn English. Language learning takes time.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;学习第二语言很难，如果你想学一门语言，你得付出很多时间。这是学习语言最重要的部分：时间。如果你不花大量时间学习，你肯定学不会。学习语言需要时间。（这段有凑字数的嫌疑）&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I am a language teacher, but I&apos;m also a language learner. I learn languages because it&apos;s fun for me, and I love talking to people from other countries. This is the best part about learning another language: You can talk to many people and make new friends. I talk to people from many different countries. This is the fun part of learning languages. But language learning is not easy.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;我是一个教语言的老师，也是一个语言学习者。学习语言是因为我觉得很有趣，我很喜欢和不同国家的人聊天。学习语言最重要的是可以和很不同国家的人聊天，认识很多新朋友。我会和不同国家的人聊天，这是学习语言最有趣的部分。但学语言并不容易。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Sometimes I get sad or frustrated when I can&apos;t understand somebody. I also get nervous when I talk to people in other languages. but that&apos;s okay, it&apos;s normal to get sad or frustrated or nervous when you learn another language.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;有时，当我不理解某人说什么时我会感到很沮丧。当我用其他语言跟人交流时也会感到紧张。但没关系；当你学习另一门语言时，感到悲伤、沮丧或紧张是正常的。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is normal. Sometimes I make big mistakes when I&apos;m speaking other languages. I make mistakes with grammar, with vocabulary, and with pronunciation. But this is normal. Everybody makes mistakes when they speak other languages. If you don&apos;t make mistakes, you won&apos;t improve. To improve, To get better, you need to make mistakes. You need to talk, you need to practice, you need to have fun. So don&apos;t worry about your mistakes. Have fun with English.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;这很正常，有时，当我说其他语言时会犯很大的错。我会犯语法、词汇和发音的错。但这很正常，每个人在说其他语言时都会犯错。如果你不犯错，就不会进步。为了进步，为了变得更牛逼，你得犯错。你得去说，去练，你得找到乐趣。所以不要担心犯错，去享受学英语的乐趣。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you don&apos;t have fun, it is harder to learn English. So here are some tips to have fun with English.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;如果你感受不到学英语的乐趣，那学起来就很困难。这里有几个小技巧可以帮助你找到学英语的乐趣。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;No. 1, read books in English that are interesting for you. Don&apos;t read boring books. Find books that you like. For example, if you like sports, read books in English about sports. If you like animals, read books in English about animals. And if you like technology, read books in English about technology. I love fiction, so I read fiction books in other languages. This helps me have fun and learn.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;第一，阅读你感兴趣的英语书，不要看无聊的书，去找你喜欢的内容。比如，如果你对运动感兴趣，就读运动相关的英语书。如果你对动物感兴趣，就读动物相关的英语书。如果你对科技感兴趣，就读科技相关的英语书。我喜欢小说，所以我会看其他语言的小说。这有助于我享受并学习语言。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Tip No. 2, watch videos in English that are interesting for you. If you like fashion and clothes, watch YouTube videos about fashion in English. If you like cars, watch YouTube videos about cars in English. It&apos;s important to read and watch things that are interesting for you.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;第二，看你感兴趣的英文视频 ，如果你喜欢时尚和服装，就看时尚相关的英语视频。如果你喜欢汽车，就看汽车相关的英语视频。阅读和观看感兴趣的英语内容很重要。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, tip No. 3, make friends who speak English and make friends who are learning English. I know it&apos;s not easy to make friends, but it will help you learn and practice your English. Find an English practice group in your city. You can look for an English practice group on meetup.com. If you can practice your English with friends, it will help you a lot.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;第三，去跟说英语和学英语的人交朋友。我知道这很难，但这对你学英语很有帮助。在你所有城市中找到学英语的组织，你也可以在meetup.com上找到。如果你能和朋友一起练习英语，那会对你有很大的帮助。（这里推荐 Toastmasters 俱乐部，国内大多数城市都有，如果你找不到，给我发私信或评论告诉我你所在城市。）&lt;/em&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Git原理与实践</title><link>https://blog.ithuo.net/posts/git-source-management-project/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/git-source-management-project/</guid><pubDate>Mon, 31 May 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Git 是当今最流行的版本控制系统,被广泛应用于软件开发领域。对于新手来说,Git 的概念和操作可能会显得有些复杂和陌生。但是,只要循序渐进地学习,很快就能掌握 Git 的精髓。让我们一步步来探索 Git 的奥秘。&lt;/p&gt;
&lt;h3&gt;本地工作区&lt;/h3&gt;
&lt;p&gt;Git 的工作流程始于本地工作区。这是您编写代码并进行修改的地方。每当您对文件进行更改时,Git 都会跟踪这些更改。&lt;/p&gt;
&lt;h3&gt;暂存区&lt;/h3&gt;
&lt;p&gt;在将更改提交到仓库之前,需要先将它们添加到暂存区。暂存区是一个临时区域,用于暂时存储您准备提交的更改。使用 &lt;code&gt;git add&lt;/code&gt; 命令可以将工作区的更改添加到暂存区。&lt;/p&gt;
&lt;h3&gt;本地仓库&lt;/h3&gt;
&lt;p&gt;本地仓库是 Git 存储所有提交记录的地方。当您使用 &lt;code&gt;git commit&lt;/code&gt; 命令时,暂存区中的更改就会被永久记录在本地仓库中。每次提交都会生成一个唯一的提交 ID,例如 &lt;code&gt;commit 3a3r0&lt;/code&gt;。&lt;/p&gt;
&lt;h3&gt;远程仓库&lt;/h3&gt;
&lt;p&gt;远程仓库是一个中央存储库,用于存放项目的所有提交记录。通过 &lt;code&gt;git push&lt;/code&gt; 命令,您可以将本地仓库中的提交推送到远程仓库。其他开发人员可以使用 &lt;code&gt;git clone&lt;/code&gt; 命令从远程仓库获取项目副本,或者使用 &lt;code&gt;git pull&lt;/code&gt; 命令获取最新的更改。&lt;/p&gt;
&lt;h3&gt;分支和标签&lt;/h3&gt;
&lt;p&gt;Git 支持创建多个分支,每个分支都可以独立地进行开发和提交。通过分支,您可以在不影响主线代码的情况下进行实验和尝试。&lt;/p&gt;
&lt;p&gt;标签则用于标记特定的提交,例如版本发布。在图中,我们可以看到 &lt;code&gt;tag v0.0.9&lt;/code&gt; 和 &lt;code&gt;tag v0.1.0&lt;/code&gt; 等标签。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/aeedf2090d97be962f5d9074dd6b98a1.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;实战演练&lt;/h3&gt;
&lt;p&gt;现在,让我们通过一个实际示例来演练 Git 的基本操作流程:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;初始化本地仓库&lt;/strong&gt;:在您的项目目录中运行 &lt;code&gt;git init&lt;/code&gt; 命令,创建一个新的本地仓库。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;添加文件到暂存区&lt;/strong&gt;:使用 &lt;code&gt;git add 文件名&lt;/code&gt; 命令将新建或修改的文件添加到暂存区。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;提交更改到本地仓库&lt;/strong&gt;:使用 &lt;code&gt;git commit -m &quot;提交说明&quot;&lt;/code&gt; 命令将暂存区中的更改提交到本地仓库。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;创建远程仓库&lt;/strong&gt;:在 GitHub、GitLab 或其他代码托管平台上创建一个新的远程仓库。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;关联本地仓库和远程仓库&lt;/strong&gt;:使用 &lt;code&gt;git remote add origin 远程仓库地址&lt;/code&gt; 命令将本地仓库与远程仓库关联起来。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;推送到远程仓库&lt;/strong&gt;:使用 &lt;code&gt;git push -u origin master&lt;/code&gt; 命令将本地仓库的提交推送到远程仓库的 master 分支。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;克隆远程仓库&lt;/strong&gt;:在其他开发环境中,使用 &lt;code&gt;git clone 远程仓库地址&lt;/code&gt; 命令从远程仓库获取项目副本。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;拉取最新更改&lt;/strong&gt;:在本地仓库中,使用 &lt;code&gt;git pull&lt;/code&gt; 命令从远程仓库获取最新的提交记录。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;就这样,您已经掌握了 Git 的基本操作流程!通过不断实践,您将能够更加熟练地使用 Git,提高团队协作效率,并确保代码的版本控制和追踪。&lt;/p&gt;
&lt;p&gt;Git 的强大功能远不止于此,还有许多高级特性等待您去探索。但是,只要掌握了这些基础知识,您就已经可以顺利地开启 Git 之旅了。保持好奇心,勇于尝试,Git 将成为您事半功倍的得力助手!&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>透析英语学习法</title><link>https://blog.ithuo.net/posts/analysis-of-english-learning-method/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/analysis-of-english-learning-method/</guid><pubDate>Fri, 11 Dec 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;最近在重新学习英语，偶然间发现有&lt;strong&gt;一起听课星球&lt;/strong&gt;的签约老师【伍君仪】的课程，一共20节，将视频转换为文本，大概的看了一遍，下面是学习笔记&lt;/p&gt;
&lt;p&gt;透析法（dialysis）是在使用英语过程中借助电子词典透过析出词汇，在提高理解程度和输出质量的同时完成语言知识积累的方法。&lt;/p&gt;
&lt;p&gt;透析法首先不是学习法，而是使用法，面向的对象是“真英语”，即英语母语人士听说读写用到的语言材料，拒绝非母语人士学习语言的教材、原著简写版、考试听力录音等“假英语”，这令你的英语从“学习级”飞跃到“使用级”，用英语去学习、工作、生活，获取语言以外的受益。&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;可控的输入：reading&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;根据自己的词汇量阅读英文内容，从绘本，童话，诗歌，小说，短篇文章甚至视频内容中理解作品想表达的意思，记录生词并在APP中重复性的记忆&lt;/p&gt;
&lt;p&gt;阅读英文原著，长篇包括原版小说（含英译版）、专业教材等图书，短篇包括英文网页、报纸、杂志等。建议读电子版以降低门槛，享受网上无穷的“真英语”资源。不必担心发光屏幕损伤视觉，那是没有科学依据的，屏幕与纸书效果基本等同。长篇图书可以放在各类阅读器app阅读，短篇可在浏览器或各种新闻客户端、新闻聚合应用app等阅读。&lt;/p&gt;
&lt;p&gt;阅读时遇到生词，采取50%自适应查词进行正透析，即隔一个查一个。“自适应”是自动适应你的个人词汇量和原著的生词密度，取得阅读理解（读懂大意）和阅读体验（减少中断）的平衡。选择生词复制后黏贴到在线词典app，根据音标拼读发音，寻找符合原文的一个义项，最后存入生词本以备复习（可设置词典app自动存入）。安卓、苹果系统都有跨app剪贴板取词的快捷操作，可减少大量切换app的动作。不查的生词也不能留下理解空缺，一定要猜意思，脑补出句子的完整内容，这个过程允许猜错、曲解，但不允许事后查词验证猜得对不对。&lt;/p&gt;
&lt;p&gt;透析法拒绝每词必查的精读，但决非“不求甚解”，也不是泛读，而要求认真执行查词、猜词操作，速度节奏上不求快，但求理解大意。自适应查词突破了过去“原著生词量多到XX比例就无法读懂”的瓶颈，让词汇量较小的初学者也能读懂“真英语”主流水平的原著，代价是开始时查词多一点，理解得慢一点，后面就随着词汇量上升就可读得越来越懂、越来越快。&lt;/p&gt;
&lt;p&gt;为了确保成功入门，建议初学者从最简单的长篇英文原著开始，例如蓝思值（Lexile）和首万词不重复词数都比较低的Magic Tree House系列，每日透析两册或大约相当于10,000单词的阅读量，连续7日完成“头七”挑战。读10本小说后再尝试读专业书。如果最简单的原著都读不懂，个人词汇量不足1000，建议从逆透析开始（参见后文）。“真英语”的短篇异质性高，导致比长篇的阅读难度更大，可通过主题聚合操作实现同质化以降低难度，方法是每个月设定一个你感兴趣的主题，例如NBA篮球，每日读一篇相关的网文，例如雅虎上的比赛报道。&lt;/p&gt;
&lt;h3&gt;失控的输入：listening&lt;/h3&gt;
&lt;p&gt;收听收看英文歌、新闻广播、电视节目、英文电影、播客直播、公开课视频等“真英语”，全面替换你每日收听收看的中文媒体。网络上各种资源很多，推荐实时播放流媒体的app，但注意避免英语学习类app提供的“假英语”。收看的时候必须不看字幕，包括英文字幕，否则对听力提升毫无意义。&lt;/p&gt;
&lt;p&gt;听力的难点在于听到生词，你是很难控制“真英语”词汇的——跟老外对话时你听不懂往往不好意思喊停，pardon多了对方也觉得烦。即使自己看视频，听不懂倒回去也是相当麻烦。因此，词汇量小必然听力差，一万以下听不懂“真英语”很正常。对此，很多人只能听词汇受控的“假英语”，那是没有任何提高的。透析法能做到的是帮你提升词汇量到一万以上，相当于强力清扫听力材料中的生词，之后你的听懂程度就会高很多。现阶段先建立听“真英语”的习惯，可采取以下措施降低听力难度：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;看英语电视节目，利用视觉信息以及熟悉的新闻内容辅助理解。&lt;/li&gt;
&lt;li&gt;每月固定听一个英文电台或看一个电视台，熟悉媒体套路。&lt;/li&gt;
&lt;li&gt;每日听新闻配合读新闻，可选视频文字并茂的全媒体类app。&lt;/li&gt;
&lt;li&gt;看英文直播（如美女/游戏），听播客等，选择感兴趣内容。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;失控的输出：speaking&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;不用专门练口语，例如去英语角之类，而是日常说话改成用英语说，方法是跟熟人约定建立口语圈，例如家人、宿舍室友，圈内跟男朋友、闺蜜、亲生儿女等说英语可降低开口焦虑，24/7说英语的机会也远超英语角。跟志同道合的网友在微信群、QQ群飙英语，更可克服时空障碍。&lt;/p&gt;
&lt;p&gt;词汇不足是口语最大的瓶颈。口语一旦说出来就相当于表演翻译，其可控性较低，体现在遇到逆向生词的情况，即不知道用英语怎么表达的中文意思，往往导致卡顿。对此，传统做法是用基础词汇对逆向生词进行英英解释，啰里啰唆“绕”出来。这是不得已而为之，对大脑灵活性、口才、熟练程度要求很高，有时状态不好就非常卡顿。况且，一些词汇不容易做英英解释，例如化学元素和一些抽象的概念。此外，这还孳生不地道、不标准的“中式英语表达”，特别是在缺少跟英语母语人士直接交流的条件下。&lt;/p&gt;
&lt;p&gt;透析法发挥词汇处理的优势应对流利的问题，原理是增加个人的词汇量，特别是逆向词汇量，即时输出的时候直接调用正确的词汇，降低因生词而不得不做英英解释的情况。&lt;/p&gt;
&lt;h3&gt;可控的输出：writing&lt;/h3&gt;
&lt;p&gt;用英语写日记，输出学习笔记，将生活的每一个值得纪念的场景用英语记录下来，编写一些小故事，去discord和line上和native speaker文字交流，国外版知乎上发帖提问，回答，在输出之前为了防止表达错误，可以将完成的句子交由GPT进行辅导训练&lt;/p&gt;
&lt;h3&gt;每日复习和打卡操作&lt;/h3&gt;
&lt;p&gt;从听说读写、正逆双向透析到的生词统一存入电子词典的生词本，每日进行一次货仓式滚动复习，范围是最近7天查过的生词。不需要用到电子词典自带的复习程序，只需在生词本简单过一遍，具体是正向生词看英文回忆中文意思，逆向生词看中文回忆英文意思，回忆不起来的生词马上看词典解释。可借助电子词典的卡片复习功能，每日在走路、坐车等的时候完成便可。这样复习容易想起你查词时的应用场景，使用过的生词记忆效果特别好，但过后遗忘也属正常。长期记忆只需不断透析，在各种场景（如小说情节、新闻播报）中生词多次重现，实现自动“复习”。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>设计一个系统需要经过哪些环节</title><link>https://blog.ithuo.net/posts/designing-a-system-process/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/designing-a-system-process/</guid><pubDate>Sun, 07 Jun 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;The Components of System Design&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/b53a711c7868ebd75fad7500024b11a0.png&quot; alt=&quot;IMG_2742.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;系统设计提供了构建应用程序的蓝图。没有经过系统设计的应用程序通常会变得一团糟，扩展与维护成本高昂。&lt;/p&gt;
&lt;p&gt;系统设计的目标是创建一个可靠、高效、安全和用户友好的系统，满足企业及其用户的需求。&lt;/p&gt;
&lt;p&gt;该过程涉及各个步骤，下面按其发生的一般顺序进行说明：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;需求分析&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;该过程首先定义系统需求。这涉及了解系统的目标、任务和约束。&lt;/p&gt;
&lt;p&gt;这个阶段尤为关键，因为它为其他阶段奠定了基础。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;顶&lt;strong&gt;层设计&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;系统的架构概述是在此阶段创建的。它描述了系统的主要组件以及它们如何相互作用。如果有需要划分领域，做领域驱动设计同样是在这个环节。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;详细设计&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;当我们大致了解整个系统的工作原理后，我们就可以设计每个组件的详细规格。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;界面设计&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;接下来是界面设计，涉及规划用户界面和应用程序编程界面。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;数据库设计&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;该过程的这一部分涉及设计表和关系，以及定义如何存储、访问和操作数据。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;安全设计&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在这一步中，我们关注一个非常重要的元素——安全性。&lt;/p&gt;
&lt;p&gt;这是我们定义系统如何保护数据、确保隐私和处理潜在威胁的地方。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;性能设计&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;本节的主要重点是初始需求分析中列出的性能标准。结果是满足这些要求的设计。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;错误处理和日志记录&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这里的重点是分析潜在的故障区域并确定系统将如何响应。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;可测试性&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;此步骤涉及确定将测试哪些组件、如何进行测试以及如何传达和使用结果。&lt;/p&gt;
&lt;p&gt;——————————————————————————————————————&lt;/p&gt;
&lt;p&gt;系统设计是一个迭代过程，涉及在上述步骤之间来回改进解决方案。&lt;/p&gt;
&lt;p&gt;明确定义的设计使应用程序开发变得更加容易，它为构建安全和高性能的系统提供了蓝图。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Ubuntu快速安装Docker</title><link>https://blog.ithuo.net/posts/quick-install-docker-on-ubuntu/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/quick-install-docker-on-ubuntu/</guid><pubDate>Sat, 18 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Docker是一种流行的容器化平台，它能够简化应用程序的部署和管理。本文将介绍在Ubuntu操作系统上安装Docker的步骤，以便我们可以开始使用Docker来构建和运行容器化应用程序。&lt;/p&gt;
&lt;p&gt;系统版本&lt;/p&gt;
&lt;p&gt;本文以Ubuntu22.04系统为例安装docker，&lt;a href=&quot;https://link.zhihu.com/?target=https%3A%2F%2Fubuntu.com%2Fdownload&quot;&gt;Ubuntu官方下载地址&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;检查卸载老版本docker&lt;/p&gt;
&lt;p&gt;ubuntu下自带了docker的库，不需要添加新的源。&lt;/p&gt;
&lt;p&gt;但是ubuntu自带的docker版本太低，需要先卸载旧的再安装新的。&lt;/p&gt;
&lt;p&gt;注：docker的旧版本不一定被称为docker，&lt;a href=&quot;https://link.zhihu.com/?target=http%3A%2F%2Fdocker.io&quot;&gt;http://docker.io&lt;/a&gt; 或 docker-engine也有可能，所以我们卸载的命令为：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;apt-get remove docker docker-engine docker.io containerd runc&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;如果不能正常卸载，出现如下情况，显示无权限时，需要添加管理员权限才可进行卸载：&lt;/p&gt;
&lt;p&gt;我们就需要使用&lt;code&gt;sudo apt-get remove docker docker-engine docker.io containerd runc&lt;/code&gt;命令使用root权限来进行卸载。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/1b318ee02d1c45a1c0c326e2f48756d8.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;安装步骤&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;更新软件包&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在终端中执行以下命令来更新Ubuntu软件包列表和已安装软件的版本:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo apt update&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo apt upgrade&lt;/code&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;安装docker依赖&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Docker在Ubuntu上依赖一些软件包。执行以下命令来安装这些依赖:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo apt-get install ca-certificates curl gnupg lsb-release&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/ff1d2e2db2b425087a12230af9a807c1.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;添加Docker官方GPG密钥&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;执行以下命令来添加Docker官方的GPG密钥:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/b5adaf704d3f2c6dfff0ac8a13aec1a5.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;结果如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;添加Docker软件源&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;执行以下命令来添加Docker的软件源:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo add-apt-repository &quot;deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable&quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/56ca8385871e6a8dc74da77ab9c28db2.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;安装docker&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;执行以下命令来安装Docker:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo apt-get install docker-ce docker-ce-cli containerd.io&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/e2af68685d709a3af4d3bbf19142ffe2.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;配置用户组（可选）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;默认情况下，只有root用户和docker组的用户才能运行Docker命令。我们可以将当前用户添加到docker组，以避免每次使用Docker时都需要使用sudo。命令如下：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo usermod -aG docker $USER&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注：重新登录才能使更改生效。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;运行docker&lt;/p&gt;
&lt;p&gt;我们可以通过启动&lt;code&gt;docker&lt;/code&gt;来验证我们是否成功安装。命令如下：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo systemctl start docker&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;安装工具&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/09b49f7fc43e7a3bae9ddbacd2aa556d.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;重启docker&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo service docker restart&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;验证是否成功&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo docker run hello-world&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;运行命令后，结果如下：&lt;/p&gt;
&lt;p&gt;因为我们之前没有拉取过&lt;code&gt;hello-world&lt;/code&gt;，所以运行命令后会出现本地没有该镜像，并且会自动拉取的操作。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;查看版本&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们可以通过下面的命令来查看&lt;code&gt;docker&lt;/code&gt;的版本&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo docker version&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;结果如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/82a0bebe76e97c15a0c9ff35dc28a445.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Firefly 布局系统详解</title><link>https://blog.ithuo.net/posts/firefly-layout-system/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/firefly-layout-system/</guid><description>深入了解 Firefly 的布局系统，包括侧边栏布局（左侧/双侧）和文章列表布局（列表/网格），以及为什么双侧边栏与网格模式会冲突的技术原理。</description><pubDate>Thu, 02 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;📖 概述&lt;/h2&gt;
&lt;p&gt;Firefly 提供了灵活的布局系统，允许您根据内容需求和个人喜好自定义博客的视觉呈现方式。布局系统主要包括&lt;strong&gt;侧边栏布局&lt;/strong&gt;和&lt;strong&gt;文章列表布局&lt;/strong&gt;两个维度，它们相互配合，共同决定了页面的整体结构。&lt;/p&gt;
&lt;p&gt;本文将详细介绍 Firefly 的各种布局模式、它们的特点、使用场景，以及为什么某些布局之间会存在冲突。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;一、侧边栏布局系统&lt;/h2&gt;
&lt;p&gt;侧边栏是博客页面的重要组成部分，用于展示导航、分类、标签、统计信息等辅助内容。Firefly 支持两种侧边栏布局模式。&lt;/p&gt;
&lt;h3&gt;1.1 左侧边栏模式 (position: &quot;left&quot;)&lt;/h3&gt;
&lt;h4&gt;特点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;侧边栏固定在页面左侧&lt;/li&gt;
&lt;li&gt;主内容区域位于右侧&lt;/li&gt;
&lt;li&gt;符合从左到右的阅读习惯&lt;/li&gt;
&lt;li&gt;适合展示导航和分类等重要信息&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;布局结构&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;./images/left.webp&quot; alt=&quot;左侧边栏布局&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- 此处可以插入左侧边栏布局截图 --&amp;gt;&lt;/p&gt;
&lt;h4&gt;适用场景&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;传统博客风格&lt;/li&gt;
&lt;li&gt;强调导航和分类的博客&lt;/li&gt;
&lt;li&gt;需要突出用户资料的个人博客&lt;/li&gt;
&lt;li&gt;内容为主，辅助信息次之的场景&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;配置示例&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// src/config/sidebarConfig.ts
export const sidebarLayoutConfig: SidebarLayoutConfig = {
  enable: true,
  position: &quot;left&quot;, // 左侧边栏
  leftComponents: [
    { type: &quot;profile&quot;, order: 1 },
    { type: &quot;announcement&quot;, order: 2 },
    { type: &quot;categories&quot;, order: 3 },
    { type: &quot;tags&quot;, order: 5 },
  ],
  rightComponents: [], // 右侧组件为空
};
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;1.2 双侧边栏模式 (position: &quot;both&quot;)&lt;/h3&gt;
&lt;h4&gt;特点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;左右两侧同时存在侧边栏&lt;/li&gt;
&lt;li&gt;主内容区域位于中间&lt;/li&gt;
&lt;li&gt;最大化利用屏幕空间&lt;/li&gt;
&lt;li&gt;可以展示更多辅助信息&lt;/li&gt;
&lt;li&gt;适合宽屏显示器&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;布局结构&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;./images/both.webp&quot; alt=&quot;双侧边栏布局&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;适用场景&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;宽屏桌面端浏览&lt;/li&gt;
&lt;li&gt;信息密集型博客&lt;/li&gt;
&lt;li&gt;需要展示大量辅助内容&lt;/li&gt;
&lt;li&gt;专业性强的技术博客&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;响应式行为&lt;/h4&gt;
&lt;p&gt;双侧边栏模式具有智能的响应式设计：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;桌面端（≥1024px）&lt;/strong&gt;：显示左右双侧边栏&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;平板端（768px-1023px）&lt;/strong&gt;：只显示左侧边栏，右侧边栏自动隐藏&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;移动端（&amp;lt;768px）&lt;/strong&gt;：只显示左侧边栏&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;配置示例&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// src/config/sidebarConfig.ts
export const sidebarLayoutConfig: SidebarLayoutConfig = {
  enable: true,
  position: &quot;both&quot;, // 双侧边栏
  leftComponents: [
    // 左侧边栏组件
    { type: &quot;profile&quot;, order: 1 },
    { type: &quot;announcement&quot;, order: 2 },
    { type: &quot;categories&quot;, order: 3 },
    { type: &quot;tags&quot;, order: 5 },
  ],
  rightComponents: [
    // 右侧边栏组件
    { type: &quot;stats&quot;, order: 1 },
    { type: &quot;sidebarToc&quot;, order: 2, showOnPostPage: true },
    { type: &quot;advertisement&quot;, order: 10 },
  ],
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;⚠️ 重要限制&lt;/h4&gt;
&lt;p&gt;启用双侧边栏后，文章列表的&lt;strong&gt;网格模式&lt;/strong&gt;将无法使用，只能使用&lt;strong&gt;列表模式&lt;/strong&gt;。原因详见下文&quot;布局冲突分析&quot;章节。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;二、文章列表布局系统&lt;/h2&gt;
&lt;p&gt;文章列表是博客首页和归档页的核心内容，Firefly 提供两种展示方式。&lt;/p&gt;
&lt;h3&gt;2.1 列表模式 (defaultMode: &quot;list&quot;)&lt;/h3&gt;
&lt;h4&gt;特点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;单列纵向排列&lt;/li&gt;
&lt;li&gt;显示文章封面图&lt;/li&gt;
&lt;li&gt;展示更多文章摘要&lt;/li&gt;
&lt;li&gt;适合深度阅读&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;列表布局结构&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;./images/left.webp&quot; alt=&quot;列表模式布局&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;优点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;✅ 视觉冲击力强，封面图吸引眼球&lt;/li&gt;
&lt;li&gt;✅ 可以展示更多文章信息（摘要、标签等）&lt;/li&gt;
&lt;li&gt;✅ 适合图片内容丰富的博客&lt;/li&gt;
&lt;li&gt;✅ 移动端友好，单列更易阅读&lt;/li&gt;
&lt;li&gt;✅ 兼容所有侧边栏配置（单侧、双侧）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;适用场景&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;摄影博客、设计博客&lt;/li&gt;
&lt;li&gt;强调视觉效果的博客&lt;/li&gt;
&lt;li&gt;文章数量较少但质量高的博客&lt;/li&gt;
&lt;li&gt;移动端访问为主的博客&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;配置示例&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// src/config/siteConfig.ts
export const siteConfig: SiteConfig = {
  postListLayout: {
    defaultMode: &quot;list&quot;, // 列表模式
    allowSwitch: true,   // 允许用户切换
  },
};
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;2.2 网格模式 (defaultMode: &quot;grid&quot;)&lt;/h3&gt;
&lt;h4&gt;特点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;双列横向排列&lt;/li&gt;
&lt;li&gt;紧凑布局，信息密度高&lt;/li&gt;
&lt;li&gt;适合快速浏览&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;网格布局结构&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;./images/grid.webp&quot; alt=&quot;网格模式布局&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;优点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;✅ 单屏显示更多文章&lt;/li&gt;
&lt;li&gt;✅ 适合快速浏览和查找&lt;/li&gt;
&lt;li&gt;✅ 节省垂直滚动空间&lt;/li&gt;
&lt;li&gt;✅ 现代化的瀑布流风格&lt;/li&gt;
&lt;li&gt;✅ 适合文章数量多的博客&lt;/li&gt;
&lt;li&gt;✅ 视觉冲击力强，封面图吸引眼球&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;瀑布流布局结构&lt;/h4&gt;
&lt;p&gt;Firefly 的网格模式内置了智能瀑布流布局支持，解决了网格布局中因图文混合文章导致的卡片高度不一致导致的空白问题。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./images/masonry.webp&quot; alt=&quot;瀑布流布局&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;智能排版&lt;/strong&gt;：采用 Z 字形分布（左右交替），严格保持文章的时间顺序。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;消除空白&lt;/strong&gt;：通过绝对定位精确计算每个卡片的位置，让卡片紧贴上一行的卡片，消除垂直方向的空白间隙。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置灵活&lt;/strong&gt;：您可以在 &lt;code&gt;siteConfig.ts&lt;/code&gt; 中通过 &lt;code&gt;postListLayout.grid.masonry&lt;/code&gt; 选项自由开启或关闭此功能。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;限制&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;⚠️ &lt;strong&gt;不支持双侧边栏模式&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;⚠️ 屏幕宽度 &amp;lt; 1200px 时自动切换为列表模式&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;适用场景&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;技术博客、文字为主的博客&lt;/li&gt;
&lt;li&gt;文章数量多，需要快速检索&lt;/li&gt;
&lt;li&gt;桌面端访问为主的博客&lt;/li&gt;
&lt;li&gt;强调信息密度的场景&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;配置示例&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// src/config/siteConfig.ts
export const siteConfig: SiteConfig = {
  postListLayout: {
    defaultMode: &quot;grid&quot;, // 网格模式
    allowSwitch: true,   // 允许用户切换
    grid: {
      masonry: true,     // 开启瀑布流布局
    },
  },
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;响应式行为&lt;/h4&gt;
&lt;p&gt;网格模式具有智能的响应式设计：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;桌面端（≥1200px）&lt;/strong&gt;：显示双列网格&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;平板端和移动端（&amp;lt;1200px）&lt;/strong&gt;：自动切换为单列列表模式&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;布局切换按钮&lt;/strong&gt;：仅在桌面端显示&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;2.2.1 封面位置：顶部 vs 右侧&lt;/h3&gt;
&lt;p&gt;网格模式支持两种封面摆放方式，通过配置进行切换：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// src/config/siteConfig.ts
export const siteConfig: SiteConfig = {
  postListLayout: {
    defaultMode: &quot;grid&quot;,
    allowSwitch: true,
    grid: {
      masonry: true,
      coverPosition: &quot;top&quot;, // 或 &quot;right&quot;
    },
  },
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;封面置于顶部（coverPosition: &quot;top&quot;）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;封面图位于卡片上方，文本在下方，整体更“图文型”，适合视觉内容丰富的文章。&lt;/li&gt;
&lt;li&gt;封面宽度占满卡片；摘要与标签在封面下自然排列，整体节奏更均衡。&lt;/li&gt;
&lt;li&gt;移动端在卡片有封面时，置顶按钮采用半透明毛玻璃背景，覆盖在图片之上也能保持可读性。&lt;/li&gt;
&lt;li&gt;与瀑布流（masonry）更契合：图文高度差异大时纵向堆叠更自然，减少左右列空白。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;./images/masonry.webp&quot; alt=&quot;顶部封面&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;封面置于右侧（coverPosition: &quot;right&quot;）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;文本在左、封面在右，更利于快速浏览文字型内容，信息密度更高。&lt;/li&gt;
&lt;li&gt;卡片高度更加稳定，列表观感更整齐；无封面文章在桌面端会显示进入按钮，便于操作。&lt;/li&gt;
&lt;li&gt;适合标题与元信息为主、封面作为辅助点缀的内容形态。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;./images/grid_cover_right.webp&quot; alt=&quot;右侧封面&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;使用建议&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;视觉型内容（摄影、设计、插图）优先选择“顶部”。&lt;/li&gt;
&lt;li&gt;文字密集、需要高效扫读的列表页优先选择“右侧”，但封面内容会变窄。&lt;/li&gt;
&lt;li&gt;图文混合且开启瀑布流时，“顶部”通常更协调&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;三、布局冲突分析 ⚠️&lt;/h2&gt;
&lt;h3&gt;3.1 为什么双侧边栏与网格模式冲突？&lt;/h3&gt;
&lt;p&gt;这是 Firefly 设计中一个重要的技术限制，理解其原因有助于您做出正确的布局选择。&lt;/p&gt;
&lt;h4&gt;空间占用分析&lt;/h4&gt;
&lt;p&gt;让我们通过实际的宽度计算来理解这个问题：&lt;/p&gt;
&lt;h5&gt;典型桌面屏幕宽度&lt;/h5&gt;
&lt;p&gt;假设常见的桌面屏幕宽度为 &lt;strong&gt;1920px&lt;/strong&gt;（Full HD）&lt;/p&gt;
&lt;h5&gt;单侧边栏 + 网格模式 ✅&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;总宽度：1920px

├─ 左侧边栏：    280px  (固定宽度)
├─ 左侧间距：     40px  (margin)
├─ 主内容区域： 1560px  (剩余空间)
│  ├─ 文章卡片1： 750px
│  ├─ 卡片间距：   60px
│  └─ 文章卡片2： 750px
└─ 右侧间距：     40px

主内容区域 = 1920 - 280 - 40 - 40 = 1560px
每列宽度   = (1560 - 60) / 2 = 750px  ✅ 足够显示
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;结论&lt;/strong&gt;：单侧边栏时，主内容区域有 &lt;strong&gt;1560px&lt;/strong&gt;，足够容纳双列网格（每列 750px），布局正常。&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- 此处可以插入单侧边栏+网格模式截图 --&amp;gt;&lt;/p&gt;
&lt;h5&gt;双侧边栏 + 网格模式 ❌&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;总宽度：1920px

├─ 左侧边栏：    280px  (固定宽度)
├─ 左侧间距：     40px  (margin)
├─ 主内容区域： 1240px  (剩余空间)
│  ├─ 文章卡片1： 590px
│  ├─ 卡片间距：   60px
│  └─ 文章卡片2： 590px
├─ 右侧间距：     40px
└─ 右侧边栏：    280px  (固定宽度)

主内容区域 = 1920 - 280 - 40 - 40 - 280 - 40 = 1240px
每列宽度   = (1240 - 60) / 2 = 590px  ❌ 空间不足
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;问题&lt;/strong&gt;：双侧边栏时，主内容区域被压缩到 &lt;strong&gt;1240px&lt;/strong&gt;，每列只有 &lt;strong&gt;590px&lt;/strong&gt;，文章卡片显得过于拥挤。&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- 此处可以插入双侧边栏+网格模式拥挤效果截图 --&amp;gt;&lt;/p&gt;
&lt;h5&gt;更小屏幕的情况&lt;/h5&gt;
&lt;p&gt;在 &lt;strong&gt;1366px&lt;/strong&gt; 宽度的笔记本电脑上：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;双侧边栏 + 网格模式

总宽度：1366px

主内容区域 = 1366 - 280 - 40 - 40 - 280 - 40 = 686px
每列宽度   = (686 - 60) / 2 = 313px  ❌ 严重不足

每列只有 313px，文章标题都无法完整显示！
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;视觉体验问题&lt;/h4&gt;
&lt;p&gt;即使在宽屏显示器上，双侧边栏 + 网格模式也会带来以下问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;文章卡片过窄&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;标题需要多行折叠&lt;/li&gt;
&lt;li&gt;摘要显示不完整&lt;/li&gt;
&lt;li&gt;标签和元信息拥挤&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;阅读体验差&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每行文字过短，阅读不流畅&lt;/li&gt;
&lt;li&gt;视线需要频繁跳转&lt;/li&gt;
&lt;li&gt;信息扫描效率低&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;视觉不平衡&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;三栏布局已经占据大量横向空间&lt;/li&gt;
&lt;li&gt;再将中间栏分成两列，过于碎片化&lt;/li&gt;
&lt;li&gt;破坏了&quot;中心内容突出&quot;的设计原则&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;布局对比图示&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;❌空间不足 双侧边栏 + 网格模式（拥挤）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;svg width=&quot;800&quot; height=&quot;200&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&amp;gt;
&amp;lt;!-- 背景 --&amp;gt;
&amp;lt;rect width=&quot;800&quot; height=&quot;200&quot; fill=&quot;#f8f9fa&quot;/&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- 左侧边栏 --&amp;gt;
&amp;lt;rect x=&quot;20&quot; y=&quot;30&quot; width=&quot;140&quot; height=&quot;140&quot; fill=&quot;#e3f2fd&quot; stroke=&quot;#2196f3&quot; stroke-width=&quot;2&quot; rx=&quot;4&quot;/&amp;gt;
&amp;lt;text x=&quot;90&quot; y=&quot;90&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; font-weight=&quot;bold&quot; fill=&quot;#1976d2&quot;&amp;gt;左侧边栏&amp;lt;/text&amp;gt;
&amp;lt;text x=&quot;90&quot; y=&quot;110&quot; text-anchor=&quot;middle&quot; font-size=&quot;12&quot; fill=&quot;#666&quot;&amp;gt;280px&amp;lt;/text&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- 文章1 --&amp;gt;
&amp;lt;rect x=&quot;180&quot; y=&quot;30&quot; width=&quot;120&quot; height=&quot;140&quot; fill=&quot;#fff3e0&quot; stroke=&quot;#ff9800&quot; stroke-width=&quot;2&quot; rx=&quot;4&quot;/&amp;gt;
&amp;lt;text x=&quot;240&quot; y=&quot;90&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; font-weight=&quot;bold&quot; fill=&quot;#f57c00&quot;&amp;gt;文章1&amp;lt;/text&amp;gt;
&amp;lt;text x=&quot;240&quot; y=&quot;110&quot; text-anchor=&quot;middle&quot; font-size=&quot;12&quot; fill=&quot;#666&quot;&amp;gt;590px&amp;lt;/text&amp;gt;
&amp;lt;text x=&quot;240&quot; y=&quot;130&quot; text-anchor=&quot;middle&quot; font-size=&quot;11&quot; fill=&quot;#d84315&quot;&amp;gt;过窄！&amp;lt;/text&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- 文章2 --&amp;gt;
&amp;lt;rect x=&quot;320&quot; y=&quot;30&quot; width=&quot;120&quot; height=&quot;140&quot; fill=&quot;#fff3e0&quot; stroke=&quot;#ff9800&quot; stroke-width=&quot;2&quot; rx=&quot;4&quot;/&amp;gt;
&amp;lt;text x=&quot;380&quot; y=&quot;90&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; font-weight=&quot;bold&quot; fill=&quot;#f57c00&quot;&amp;gt;文章2&amp;lt;/text&amp;gt;
&amp;lt;text x=&quot;380&quot; y=&quot;110&quot; text-anchor=&quot;middle&quot; font-size=&quot;12&quot; fill=&quot;#666&quot;&amp;gt;590px&amp;lt;/text&amp;gt;
&amp;lt;text x=&quot;380&quot; y=&quot;130&quot; text-anchor=&quot;middle&quot; font-size=&quot;11&quot; fill=&quot;#d84315&quot;&amp;gt;过窄！&amp;lt;/text&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- 右侧边栏 --&amp;gt;
&amp;lt;rect x=&quot;460&quot; y=&quot;30&quot; width=&quot;140&quot; height=&quot;140&quot; fill=&quot;#e3f2fd&quot; stroke=&quot;#2196f3&quot; stroke-width=&quot;2&quot; rx=&quot;4&quot;/&amp;gt;
&amp;lt;text x=&quot;530&quot; y=&quot;90&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; font-weight=&quot;bold&quot; fill=&quot;#1976d2&quot;&amp;gt;右侧边栏&amp;lt;/text&amp;gt;
&amp;lt;text x=&quot;530&quot; y=&quot;110&quot; text-anchor=&quot;middle&quot; font-size=&quot;12&quot; fill=&quot;#666&quot;&amp;gt;280px&amp;lt;/text&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- 箭头指示 --&amp;gt;
&amp;lt;path d=&quot;M 240 180 L 240 195&quot; stroke=&quot;#d32f2f&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrowred)&quot;/&amp;gt;
&amp;lt;path d=&quot;M 380 180 L 380 195&quot; stroke=&quot;#d32f2f&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrowred)&quot;/&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;defs&amp;gt;
&amp;lt;marker id=&quot;arrowred&quot; markerWidth=&quot;10&quot; markerHeight=&quot;10&quot; refX=&quot;5&quot; refY=&quot;5&quot; orient=&quot;auto&quot;&amp;gt;
&amp;lt;path d=&quot;M 0 0 L 10 5 L 0 10 Z&quot; fill=&quot;#d32f2f&quot;/&amp;gt;
&amp;lt;/marker&amp;gt;
&amp;lt;/defs&amp;gt;
&amp;lt;/svg&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;✅布局合理：双侧边栏 + 列表模式（舒适）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;svg width=&quot;800&quot; height=&quot;200&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&amp;gt;
&amp;lt;!-- 背景 --&amp;gt;
&amp;lt;rect width=&quot;800&quot; height=&quot;200&quot; fill=&quot;#f8f9fa&quot;/&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- 左侧边栏 --&amp;gt;
&amp;lt;rect x=&quot;20&quot; y=&quot;30&quot; width=&quot;140&quot; height=&quot;140&quot; fill=&quot;#e3f2fd&quot; stroke=&quot;#2196f3&quot; stroke-width=&quot;2&quot; rx=&quot;4&quot;/&amp;gt;
&amp;lt;text x=&quot;90&quot; y=&quot;90&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; font-weight=&quot;bold&quot; fill=&quot;#1976d2&quot;&amp;gt;左侧边栏&amp;lt;/text&amp;gt;
&amp;lt;text x=&quot;90&quot; y=&quot;110&quot; text-anchor=&quot;middle&quot; font-size=&quot;12&quot; fill=&quot;#666&quot;&amp;gt;280px&amp;lt;/text&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- 文章列表区域 --&amp;gt;
&amp;lt;rect x=&quot;180&quot; y=&quot;30&quot; width=&quot;320&quot; height=&quot;140&quot; fill=&quot;#e8f5e9&quot; stroke=&quot;#4caf50&quot; stroke-width=&quot;2&quot; rx=&quot;4&quot;/&amp;gt;
&amp;lt;text x=&quot;340&quot; y=&quot;85&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; font-weight=&quot;bold&quot; fill=&quot;#2e7d32&quot;&amp;gt;文章列表&amp;lt;/text&amp;gt;
&amp;lt;text x=&quot;340&quot; y=&quot;105&quot; text-anchor=&quot;middle&quot; font-size=&quot;12&quot; fill=&quot;#666&quot;&amp;gt;1240px&amp;lt;/text&amp;gt;
&amp;lt;text x=&quot;340&quot; y=&quot;125&quot; text-anchor=&quot;middle&quot; font-size=&quot;11&quot; fill=&quot;#388e3c&quot;&amp;gt;单列，空间充足&amp;lt;/text&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- 右侧边栏 --&amp;gt;
&amp;lt;rect x=&quot;520&quot; y=&quot;30&quot; width=&quot;140&quot; height=&quot;140&quot; fill=&quot;#e3f2fd&quot; stroke=&quot;#2196f3&quot; stroke-width=&quot;2&quot; rx=&quot;4&quot;/&amp;gt;
&amp;lt;text x=&quot;590&quot; y=&quot;90&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; font-weight=&quot;bold&quot; fill=&quot;#1976d2&quot;&amp;gt;右侧边栏&amp;lt;/text&amp;gt;
&amp;lt;text x=&quot;590&quot; y=&quot;110&quot; text-anchor=&quot;middle&quot; font-size=&quot;12&quot; fill=&quot;#666&quot;&amp;gt;280px&amp;lt;/text&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- 箭头指示 --&amp;gt;
&amp;lt;path d=&quot;M 340 180 L 340 195&quot; stroke=&quot;#4caf50&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrowgreen)&quot;/&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;defs&amp;gt;
&amp;lt;marker id=&quot;arrowgreen&quot; markerWidth=&quot;10&quot; markerHeight=&quot;10&quot; refX=&quot;5&quot; refY=&quot;5&quot; orient=&quot;auto&quot;&amp;gt;
&amp;lt;path d=&quot;M 0 0 L 10 5 L 0 10 Z&quot; fill=&quot;#4caf50&quot;/&amp;gt;
&amp;lt;/marker&amp;gt;
&amp;lt;/defs&amp;gt;
&amp;lt;/svg&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;✅ 布局合理：单侧边栏 + 网格模式（舒适）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;svg width=&quot;800&quot; height=&quot;200&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&amp;gt;
&amp;lt;!-- 背景 --&amp;gt;
&amp;lt;rect width=&quot;800&quot; height=&quot;200&quot; fill=&quot;#f8f9fa&quot;/&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- 左侧边栏 --&amp;gt;
&amp;lt;rect x=&quot;20&quot; y=&quot;30&quot; width=&quot;140&quot; height=&quot;140&quot; fill=&quot;#e3f2fd&quot; stroke=&quot;#2196f3&quot; stroke-width=&quot;2&quot; rx=&quot;4&quot;/&amp;gt;
&amp;lt;text x=&quot;90&quot; y=&quot;90&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; font-weight=&quot;bold&quot; fill=&quot;#1976d2&quot;&amp;gt;左侧边栏&amp;lt;/text&amp;gt;
&amp;lt;text x=&quot;90&quot; y=&quot;110&quot; text-anchor=&quot;middle&quot; font-size=&quot;12&quot; fill=&quot;#666&quot;&amp;gt;280px&amp;lt;/text&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- 文章1 --&amp;gt;
&amp;lt;rect x=&quot;180&quot; y=&quot;30&quot; width=&quot;180&quot; height=&quot;140&quot; fill=&quot;#e8f5e9&quot; stroke=&quot;#4caf50&quot; stroke-width=&quot;2&quot; rx=&quot;4&quot;/&amp;gt;
&amp;lt;text x=&quot;270&quot; y=&quot;85&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; font-weight=&quot;bold&quot; fill=&quot;#2e7d32&quot;&amp;gt;文章1&amp;lt;/text&amp;gt;
&amp;lt;text x=&quot;270&quot; y=&quot;105&quot; text-anchor=&quot;middle&quot; font-size=&quot;12&quot; fill=&quot;#666&quot;&amp;gt;750px&amp;lt;/text&amp;gt;
&amp;lt;text x=&quot;270&quot; y=&quot;125&quot; text-anchor=&quot;middle&quot; font-size=&quot;11&quot; fill=&quot;#388e3c&quot;&amp;gt;宽度充足&amp;lt;/text&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- 文章2 --&amp;gt;
&amp;lt;rect x=&quot;380&quot; y=&quot;30&quot; width=&quot;180&quot; height=&quot;140&quot; fill=&quot;#e8f5e9&quot; stroke=&quot;#4caf50&quot; stroke-width=&quot;2&quot; rx=&quot;4&quot;/&amp;gt;
&amp;lt;text x=&quot;470&quot; y=&quot;85&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; font-weight=&quot;bold&quot; fill=&quot;#2e7d32&quot;&amp;gt;文章2&amp;lt;/text&amp;gt;
&amp;lt;text x=&quot;470&quot; y=&quot;105&quot; text-anchor=&quot;middle&quot; font-size=&quot;12&quot; fill=&quot;#666&quot;&amp;gt;750px&amp;lt;/text&amp;gt;
&amp;lt;text x=&quot;470&quot; y=&quot;125&quot; text-anchor=&quot;middle&quot; font-size=&quot;11&quot; fill=&quot;#388e3c&quot;&amp;gt;宽度充足&amp;lt;/text&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- 箭头指示 --&amp;gt;
&amp;lt;path d=&quot;M 270 180 L 270 195&quot; stroke=&quot;#4caf50&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrowgreen2)&quot;/&amp;gt;
&amp;lt;path d=&quot;M 470 180 L 470 195&quot; stroke=&quot;#4caf50&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrowgreen2)&quot;/&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;defs&amp;gt;
&amp;lt;marker id=&quot;arrowgreen2&quot; markerWidth=&quot;10&quot; markerHeight=&quot;10&quot; refX=&quot;5&quot; refY=&quot;5&quot; orient=&quot;auto&quot;&amp;gt;
&amp;lt;path d=&quot;M 0 0 L 10 5 L 0 10 Z&quot; fill=&quot;#4caf50&quot;/&amp;gt;
&amp;lt;/marker&amp;gt;
&amp;lt;/defs&amp;gt;
&amp;lt;/svg&amp;gt;&lt;/p&gt;
&lt;h3&gt;3.2 技术实现层面&lt;/h3&gt;
&lt;p&gt;从代码实现角度，Firefly 采用了以下策略：&lt;/p&gt;
&lt;h4&gt;自动冲突检测&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// src/utils/layout-utils.ts (示例)

// 检测布局冲突
function canUseGridLayout(): boolean {
  const { position } = sidebarLayoutConfig;
  
  // 如果启用了双侧边栏，禁用网格模式
  if (position === &quot;both&quot;) {
    return false;
  }
  
  return true;
}

// 自动修正布局
function getActualLayoutMode(): &quot;list&quot; | &quot;grid&quot; {
  const { defaultMode } = siteConfig.postListLayout;
  
  if (defaultMode === &quot;grid&quot; &amp;amp;&amp;amp; !canUseGridLayout()) {
    console.warn(&quot;网格模式与双侧边栏冲突，已自动切换为列表模式&quot;);
    return &quot;list&quot;;
  }
  
  return defaultMode;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;布局切换按钮行为&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// 双侧边栏时，隐藏布局切换按钮
const showLayoutSwitch = 
  siteConfig.postListLayout.allowSwitch &amp;amp;&amp;amp; 
  sidebarLayoutConfig.position !== &quot;both&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3.3 设计建议&lt;/h3&gt;
&lt;p&gt;根据以上分析，我们给出以下布局组合建议：&lt;/p&gt;
&lt;h4&gt;✅ 推荐组合&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;侧边栏模式&lt;/th&gt;
&lt;th&gt;文章列表模式&lt;/th&gt;
&lt;th&gt;推荐度&lt;/th&gt;
&lt;th&gt;适用场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;左侧边栏&lt;/td&gt;
&lt;td&gt;列表模式&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;传统博客风格，视觉效果好&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;左侧边栏&lt;/td&gt;
&lt;td&gt;网格模式&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;快速浏览，信息密集&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;双侧边栏&lt;/td&gt;
&lt;td&gt;列表模式&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;宽屏显示，信息丰富&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;❌ 不推荐/不支持组合&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;侧边栏模式&lt;/th&gt;
&lt;th&gt;文章列表模式&lt;/th&gt;
&lt;th&gt;推荐度&lt;/th&gt;
&lt;th&gt;原因&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;双侧边栏&lt;/td&gt;
&lt;td&gt;网格模式&lt;/td&gt;
&lt;td&gt;❌ 禁止&lt;/td&gt;
&lt;td&gt;主内容区域过窄，体验差&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;四、响应式布局行为&lt;/h2&gt;
&lt;p&gt;Firefly 的布局系统具有智能的响应式设计，会根据屏幕尺寸自动调整。&lt;/p&gt;
&lt;h3&gt;4.1 断点定义&lt;/h3&gt;
&lt;p&gt;Firefly 使用 Tailwind CSS 标准断点：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;断点名称&lt;/th&gt;
&lt;th&gt;屏幕宽度&lt;/th&gt;
&lt;th&gt;设备类型&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mobile&lt;/td&gt;
&lt;td&gt;&amp;lt; 768px&lt;/td&gt;
&lt;td&gt;手机&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tablet&lt;/td&gt;
&lt;td&gt;768px - 1023px&lt;/td&gt;
&lt;td&gt;平板&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Desktop&lt;/td&gt;
&lt;td&gt;≥ 1024px&lt;/td&gt;
&lt;td&gt;桌面&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wide Desktop&lt;/td&gt;
&lt;td&gt;≥ 1200px&lt;/td&gt;
&lt;td&gt;宽屏桌面&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;4.2 侧边栏响应式规则&lt;/h3&gt;
&lt;h4&gt;单侧边栏模式&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Desktop (≥1024px)&lt;/strong&gt;：显示侧边栏&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tablet (768px-1023px)&lt;/strong&gt;：显示侧边栏&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mobile (&amp;lt;768px)&lt;/strong&gt;：显示侧边栏（可配置隐藏）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;双侧边栏模式&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Desktop (≥1024px)&lt;/strong&gt;：显示左右双侧边栏&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tablet (768px-1023px)&lt;/strong&gt;：只显示左侧边栏&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mobile (&amp;lt;768px)&lt;/strong&gt;：只显示左侧边栏&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4.3 文章列表响应式规则&lt;/h3&gt;
&lt;h4&gt;列表模式&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;所有屏幕尺寸&lt;/strong&gt;：始终单列显示&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mobile&lt;/strong&gt;：缩小间距和卡片内边距&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;网格模式&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Wide Desktop (≥1200px)&lt;/strong&gt;：双列网格&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tablet &amp;amp; Mobile (&amp;lt;1200px)&lt;/strong&gt;：自动切换为单列列表&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;布局切换按钮&lt;/strong&gt;：仅在 ≥1200px 时显示&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;五、布局选择指南&lt;/h2&gt;
&lt;h3&gt;5.1 基于内容类型选择&lt;/h3&gt;
&lt;h4&gt;摄影/设计博客&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// 推荐：左侧边栏 + 列表模式
position: &quot;left&quot;
defaultMode: &quot;list&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;原因&lt;/strong&gt;：列表模式可以展示精美的封面图，突出视觉效果。&lt;/p&gt;
&lt;h4&gt;技术博客&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// 方案1：左侧边栏 + 网格模式
position: &quot;left&quot;
defaultMode: &quot;grid&quot;

// 方案2：双侧边栏 + 列表模式
position: &quot;both&quot;
defaultMode: &quot;list&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;原因&lt;/strong&gt;：技术博客文章多，网格模式便于快速查找；或使用双侧边栏展示更多分类和标签。&lt;/p&gt;
&lt;h4&gt;个人日记&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// 推荐：左侧边栏 + 列表模式
position: &quot;left&quot;
defaultMode: &quot;list&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;原因&lt;/strong&gt;：突出内容，营造亲切感。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;七、常见问题&lt;/h2&gt;
&lt;h3&gt;Q1: 为什么我配置了网格模式，但页面还是显示列表？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A&lt;/strong&gt;: 检查以下几点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;侧边栏是否配置为双侧边栏（&lt;code&gt;position: &quot;both&quot;&lt;/code&gt;）？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果是，网格模式会被自动禁用&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;屏幕宽度是否小于 1200px？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;网格模式仅在宽屏桌面端生效&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;浏览器是否缓存了旧的设置？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;清除 localStorage 中的布局偏好&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Q2: 双侧边栏在我的笔记本上显示不正常怎么办？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A&lt;/strong&gt;: 双侧边栏需要较大的屏幕宽度（建议 ≥1400px）。解决方案：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用外接显示器&lt;/li&gt;
&lt;li&gt;切换为单侧边栏模式&lt;/li&gt;
&lt;li&gt;配置响应式布局，让平板端自动隐藏右侧边栏&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Q3: 可以让移动端也显示网格模式吗？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A&lt;/strong&gt;: 不建议。移动端屏幕太窄，双列网格会导致文章卡片过窄，严重影响阅读体验。Firefly 已自动在小屏幕上切换为列表模式。&lt;/p&gt;
&lt;h3&gt;Q4: 布局切换按钮在哪里？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A&lt;/strong&gt;: 布局切换按钮位于导航栏右侧，但需要满足以下条件：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;siteConfig.postListLayout.allowSwitch&lt;/code&gt; 为 &lt;code&gt;true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;侧边栏不是双侧边栏模式&lt;/li&gt;
&lt;li&gt;屏幕宽度 ≥ 1200px&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Q5: 可以禁用侧边栏只显示主内容吗？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A&lt;/strong&gt;: 可以，设置 &lt;code&gt;sidebarLayoutConfig.enable = false&lt;/code&gt; 即可。但不建议这样做，因为会失去导航和辅助信息。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;八、总结&lt;/h2&gt;
&lt;p&gt;Firefly 的布局系统设计遵循以下原则：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;内容为王&lt;/strong&gt;：确保主内容区域有足够的空间&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;响应式优先&lt;/strong&gt;：自动适配不同设备&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用户友好&lt;/strong&gt;：提供灵活的配置选项&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能考虑&lt;/strong&gt;：避免过度复杂的布局组合&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;核心要点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ 单侧边栏 + 列表模式：最通用，适合大多数场景&lt;/li&gt;
&lt;li&gt;✅ 单侧边栏 + 网格模式：适合内容密集型博客&lt;/li&gt;
&lt;li&gt;✅ 双侧边栏 + 列表模式：适合宽屏显示，信息丰富&lt;/li&gt;
&lt;li&gt;❌ 双侧边栏 + 网格模式：&lt;strong&gt;不支持&lt;/strong&gt;，会导致布局拥挤&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;布局冲突的本质&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;双侧边栏已经占据了大量横向空间（560px），再将主内容区域分成双列，会导致每列宽度不足（590px），严重影响阅读体验。这是一个设计上的合理限制，而非技术缺陷。&lt;/p&gt;
&lt;p&gt;选择适合您的布局组合，让您的博客既美观又实用！&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;相关链接&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;📚 &lt;a href=&quot;https://docs-firefly.cuteleaf.cn/config/sidebarConfig-usage/&quot;&gt;侧边栏配置文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;📚 &lt;a href=&quot;https://docs-firefly.cuteleaf.cn/config/siteConfig-usage/&quot;&gt;站点配置文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;🏠 &lt;a href=&quot;https://docs-firefly.cuteleaf.cn/&quot;&gt;Firefly 官方文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;⭐ &lt;a href=&quot;https://github.com/CuteLeaf/Firefly&quot;&gt;Firefly GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Derick</author></item><item><title>Firefly 代码块示例</title><link>https://blog.ithuo.net/posts/code-examples/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/code-examples/</guid><description>在Firefly中使用表达性代码的代码块在 Markdown 中的外观。</description><pubDate>Thu, 02 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在这里，我们将探索如何使用 &lt;a href=&quot;https://expressive-code.com/&quot;&gt;Expressive Code&lt;/a&gt; 展示代码块。提供的示例基于官方文档，您可以参考以获取更多详细信息。&lt;/p&gt;
&lt;h2&gt;表达性代码&lt;/h2&gt;
&lt;h3&gt;语法高亮&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://expressive-code.com/key-features/syntax-highlighting/&quot;&gt;语法高亮&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;常规语法高亮&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;console.log(&apos;此代码有语法高亮!&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;渲染 ANSI 转义序列&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;ANSI colors:
- Regular: [31mRed[0m [32mGreen[0m [33mYellow[0m [34mBlue[0m [35mMagenta[0m [36mCyan[0m
- Bold:    [1;31mRed[0m [1;32mGreen[0m [1;33mYellow[0m [1;34mBlue[0m [1;35mMagenta[0m [1;36mCyan[0m
- Dimmed:  [2;31mRed[0m [2;32mGreen[0m [2;33mYellow[0m [2;34mBlue[0m [2;35mMagenta[0m [2;36mCyan[0m

256 colors (showing colors 160-177):
[38;5;160m160 [38;5;161m161 [38;5;162m162 [38;5;163m163 [38;5;164m164 [38;5;165m165[0m
[38;5;166m166 [38;5;167m167 [38;5;168m168 [38;5;169m169 [38;5;170m170 [38;5;171m171[0m
[38;5;172m172 [38;5;173m173 [38;5;174m174 [38;5;175m175 [38;5;176m176 [38;5;177m177[0m

Full RGB colors:
[38;2;34;139;34mForestGreen - RGB(34, 139, 34)[0m

Text formatting: [1mBold[0m [2mDimmed[0m [3mItalic[0m [4mUnderline[0m
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;编辑器和终端框架&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://expressive-code.com/key-features/frames/&quot;&gt;编辑器和终端框架&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;代码编辑器框架&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;console.log(&apos;标题属性示例&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- src/content/index.html --&amp;gt;
&amp;lt;div&amp;gt;文件名注释示例&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;终端框架&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;echo &quot;此终端框架没有标题&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;Write-Output &quot;这个有标题!&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;覆盖框架类型&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;echo &quot;看，没有框架!&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;# 如果不覆盖，这将是一个终端框架
function Watch-Tail { Get-Content -Tail 20 -Wait $args }
New-Alias tail Watch-Tail
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;文本和行标记&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://expressive-code.com/key-features/text-markers/&quot;&gt;文本和行标记&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;标记整行和行范围&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// 第1行 - 通过行号定位
// 第2行
// 第3行
// 第4行 - 通过行号定位
// 第5行
// 第6行
// 第7行 - 通过范围 &quot;7-8&quot; 定位
// 第8行 - 通过范围 &quot;7-8&quot; 定位
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;选择行标记类型 (mark, ins, del)&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;function demo() {
  console.log(&apos;此行标记为已删除&apos;)
  // 此行和下一行标记为已插入
  console.log(&apos;这是第二个插入行&apos;)

  return &apos;此行使用中性默认标记类型&apos;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;为行标记添加标签&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// labeled-line-markers.jsx
&amp;lt;button
  role=&quot;button&quot;
  {...props}
  value={value}
  className={buttonClassName}
  disabled={disabled}
  active={active}
&amp;gt;
  {children &amp;amp;&amp;amp;
    !active &amp;amp;&amp;amp;
    (typeof children === &apos;string&apos; ? &amp;lt;span&amp;gt;{children}&amp;lt;/span&amp;gt; : children)}
&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;在单独行上添加长标签&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// labeled-line-markers.jsx
&amp;lt;button
  role=&quot;button&quot;
  {...props}

  value={value}
  className={buttonClassName}

  disabled={disabled}
  active={active}
&amp;gt;

  {children &amp;amp;&amp;amp;
    !active &amp;amp;&amp;amp;
    (typeof children === &apos;string&apos; ? &amp;lt;span&amp;gt;{children}&amp;lt;/span&amp;gt; : children)}
&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;使用类似 diff 的语法&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;+此行将标记为已插入
-此行将标记为已删除
这是常规行
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
+this is an actual diff file
-all contents will remain unmodified
 no whitespace will be removed either
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;结合语法高亮和类似 diff 的语法&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;  function thisIsJavaScript() {
    // 整个块都会以 JavaScript 高亮显示，
    // 并且我们仍然可以为其添加 diff 标记！
-   console.log(&apos;要删除的旧代码&apos;)
+   console.log(&apos;新的闪亮代码！&apos;)
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;标记行内的单独文本&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;function demo() {
  // 标记行内的任何给定文本
  return &apos;支持给定文本的多个匹配项&apos;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;正则表达式&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;console.log(&apos;单词 yes 和 yep 将被标记。&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;转义正斜杠&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;echo &quot;Test&quot; &amp;gt; /home/test.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;选择内联标记类型 (mark, ins, del)&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;function demo() {
  console.log(&apos;这些是插入和删除的标记类型&apos;);
  // return 语句使用默认标记类型
  return true;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;自动换行&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://expressive-code.com/key-features/word-wrap/&quot;&gt;自动换行&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;为每个块配置自动换行&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// 启用换行的示例
function getLongString() {
  return &apos;这是一个非常长的字符串，除非容器极宽，否则很可能无法适应可用空间&apos;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;// wrap=false 的示例
function getLongString() {
  return &apos;这是一个非常长的字符串，除非容器极宽，否则很可能无法适应可用空间&apos;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;配置换行的缩进&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// preserveIndent 示例（默认启用）
function getLongString() {
  return &apos;这是一个非常长的字符串，除非容器极宽，否则很可能无法适应可用空间&apos;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;// preserveIndent=false 的示例
function getLongString() {
  return &apos;这是一个非常长的字符串，除非容器极宽，否则很可能无法适应可用空间&apos;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;可折叠部分&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://expressive-code.com/plugins/collapsible-sections/&quot;&gt;可折叠部分&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 所有这些样板设置代码将被折叠
import { someBoilerplateEngine } from &apos;@example/some-boilerplate&apos;
import { evenMoreBoilerplate } from &apos;@example/even-more-boilerplate&apos;

const engine = someBoilerplateEngine(evenMoreBoilerplate())

// 这部分代码默认可见
engine.doSomething(1, 2, 3, calcFn)

function calcFn() {
  // 您可以有多个折叠部分
  const a = 1
  const b = 2
  const c = a + b

  // 这将保持可见
  console.log(`计算结果: ${a} + ${b} = ${c}`)
  return c
}

// 直到块末尾的所有代码将再次被折叠
engine.closeConnection()
engine.freeMemory()
engine.shutdown({ reason: &apos;示例样板代码结束&apos; })
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;行号&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://expressive-code.com/plugins/line-numbers/&quot;&gt;行号&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;为每个块显示行号&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// 此代码块将显示行号
console.log(&apos;来自第2行的问候!&apos;)
console.log(&apos;我在第3行&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;// 此块禁用行号
console.log(&apos;你好?&apos;)
console.log(&apos;抱歉，你知道我在第几行吗?&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;更改起始行号&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;console.log(&apos;来自第5行的问候!&apos;)
console.log(&apos;我在第6行&apos;)
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>Derick</author></item><item><title>KaTeX 数学公式示例</title><link>https://blog.ithuo.net/posts/katex-math-example/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/katex-math-example/</guid><description>展示 Firefly 主题对 KaTeX 数学公式的支持，包括行内公式、块级公式和复杂数学符号。</description><pubDate>Wed, 01 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;本文展示了 &lt;a href=&quot;https://github.com/CuteLeaf/Firefly&quot;&gt;Firefly&lt;/a&gt; 主题对 KaTeX 数学公式的渲染支持。&lt;/p&gt;
&lt;h2&gt;行内公式 (Inline)&lt;/h2&gt;
&lt;p&gt;行内公式使用单个 &lt;code&gt;$&lt;/code&gt; 符号包裹。&lt;/p&gt;
&lt;p&gt;例如：欧拉公式 $e^{i\pi} + 1 = 0$ 是数学中最优美的公式之一。&lt;/p&gt;
&lt;p&gt;质能方程 $E = mc^2$ 也是家喻户晓。&lt;/p&gt;
&lt;h2&gt;块级公式 (Block)&lt;/h2&gt;
&lt;p&gt;块级公式使用两个 &lt;code&gt;$$&lt;/code&gt; 符号包裹，会居中显示。&lt;/p&gt;
&lt;p&gt;$$
\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}
$$&lt;/p&gt;
&lt;p&gt;$$
x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}
$$&lt;/p&gt;
&lt;h2&gt;复杂示例&lt;/h2&gt;
&lt;h3&gt;矩阵 (Matrices)&lt;/h3&gt;
&lt;p&gt;$$
\begin{pmatrix}
a &amp;amp; b \
c &amp;amp; d
\end{pmatrix}
\begin{pmatrix}
\alpha &amp;amp; \beta \
\gamma &amp;amp; \delta
\end{pmatrix} =
\begin{pmatrix}
a\alpha + b\gamma &amp;amp; a\beta + b\delta \
c\alpha + d\gamma &amp;amp; c\beta + d\delta
\end{pmatrix}
$$&lt;/p&gt;
&lt;h3&gt;极限与求和 (Limits and Sums)&lt;/h3&gt;
&lt;p&gt;$$
\sum_{n=1}^{\infty} \frac{1}{n^2} = \frac{\pi^2}{6}
$$&lt;/p&gt;
&lt;p&gt;$$
\lim_{x \to 0} \frac{\sin x}{x} = 1
$$&lt;/p&gt;
&lt;h3&gt;麦克斯韦方程组 (Maxwell&apos;s Equations)&lt;/h3&gt;
&lt;p&gt;$$
\begin{aligned}
\nabla \cdot \mathbf{E} &amp;amp;= \frac{\rho}{\varepsilon_0} \
\nabla \cdot \mathbf{B} &amp;amp;= 0 \
\nabla \times \mathbf{E} &amp;amp;= -\frac{\partial \mathbf{B}}{\partial t} \
\nabla \times \mathbf{B} &amp;amp;= \mu_0\mathbf{J} + \mu_0\varepsilon_0\frac{\partial \mathbf{E}}{\partial t}
\end{aligned}
$$&lt;/p&gt;
&lt;h3&gt;化学方程式 (Chemical Equations)&lt;/h3&gt;
&lt;p&gt;$$
\ce{CH4 + 2O2 -&amp;gt; CO2 + 2H2O}
$$&lt;/p&gt;
&lt;h2&gt;更多符号&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;符号&lt;/th&gt;
&lt;th&gt;代码&lt;/th&gt;
&lt;th&gt;渲染结果&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Alpha&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\alpha&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$\alpha$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Beta&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\beta&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$\beta$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gamma&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\Gamma&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$\Gamma$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pi&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\pi&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$\pi$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Infinity&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\infty&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$\infty$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Right Arrow&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\rightarrow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$\rightarrow$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\partial&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$\partial$&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;更多 KaTeX 语法请参考 &lt;a href=&quot;https://katex.org/docs/supported.html&quot;&gt;KaTeX Supported Functions&lt;/a&gt;。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Markdown Mermaid 图表</title><link>https://blog.ithuo.net/posts/markdown-mermaid/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/markdown-mermaid/</guid><description>一个包含 Mermaid 的 Markdown 博客文章简单示例。</description><pubDate>Wed, 01 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Markdown 中 Mermaid 图表完整指南&lt;/h1&gt;
&lt;p&gt;本文演示如何在 Markdown 文档中使用 Mermaid 创建各种复杂图表，包括流程图、时序图、甘特图、类图和状态图。&lt;/p&gt;
&lt;h2&gt;流程图示例&lt;/h2&gt;
&lt;p&gt;流程图非常适合表示流程或算法步骤。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;graph TD
    A[开始] --&amp;gt; B{条件检查}
    B --&amp;gt;|是| C[处理步骤 1]
    B --&amp;gt;|否| D[处理步骤 2]
    C --&amp;gt; E[子过程]
    D --&amp;gt; E
    subgraph E [子过程详情]
        E1[子步骤 1] --&amp;gt; E2[子步骤 2]
        E2 --&amp;gt; E3[子步骤 3]
    end
    E --&amp;gt; F{另一个决策}
    F --&amp;gt;|选项 1| G[结果 1]
    F --&amp;gt;|选项 2| H[结果 2]
    F --&amp;gt;|选项 3| I[结果 3]
    G --&amp;gt; J[结束]
    H --&amp;gt; J
    I --&amp;gt; J
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;时序图示例&lt;/h2&gt;
&lt;p&gt;时序图显示对象之间随时间的交互。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sequenceDiagram
    participant User as 用户
    participant WebApp as 网页应用
    participant Server as 服务器
    participant Database as 数据库

    User-&amp;gt;&amp;gt;WebApp: 提交登录请求
    WebApp-&amp;gt;&amp;gt;Server: 发送认证请求
    Server-&amp;gt;&amp;gt;Database: 查询用户凭据
    Database--&amp;gt;&amp;gt;Server: 返回用户数据
    Server--&amp;gt;&amp;gt;WebApp: 返回认证结果
    
    alt 认证成功
        WebApp-&amp;gt;&amp;gt;User: 显示欢迎页面
        WebApp-&amp;gt;&amp;gt;Server: 请求用户数据
        Server-&amp;gt;&amp;gt;Database: 获取用户偏好
        Database--&amp;gt;&amp;gt;Server: 返回偏好设置
        Server--&amp;gt;&amp;gt;WebApp: 返回用户数据
        WebApp-&amp;gt;&amp;gt;User: 加载个性化界面
    else 认证失败
        WebApp-&amp;gt;&amp;gt;User: 显示错误消息
        WebApp-&amp;gt;&amp;gt;User: 提示重新输入
    end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;甘特图示例&lt;/h2&gt;
&lt;p&gt;甘特图非常适合显示项目进度和时间线。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gantt
    title 网站开发项目时间线
    dateFormat  YYYY-MM-DD
    axisFormat  %m/%d
    
    section 设计阶段
    需求分析      :a1, 2023-10-01, 7d
    UI设计                 :a2, after a1, 10d
    原型创建        :a3, after a2, 5d
    
    section 开发阶段
    前端开发      :b1, 2023-10-20, 15d
    后端开发       :b2, after a2, 18d
    数据库设计           :b3, after a1, 12d
    
    section 测试阶段
    单元测试              :c1, after b1, 8d
    集成测试       :c2, after b2, 10d
    用户验收测试   :c3, after c2, 7d
    
    section 部署
    生产环境部署     :d1, after c3, 3d
    发布                    :milestone, after d1, 0d
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;类图示例&lt;/h2&gt;
&lt;p&gt;类图显示系统的静态结构，包括类、属性、方法及其关系。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;classDiagram
    class User {
        +String username
        +String password
        +String email
        +Boolean active
        +login()
        +logout()
        +updateProfile()
    }
    
    class Article {
        +String title
        +String content
        +Date publishDate
        +Boolean published
        +publish()
        +edit()
        +delete()
    }
    
    class Comment {
        +String content
        +Date commentDate
        +addComment()
        +deleteComment()
    }
    
    class Category {
        +String name
        +String description
        +addArticle()
        +removeArticle()
    }
    
    User &quot;1&quot; -- &quot;*&quot; Article : 写作
    User &quot;1&quot; -- &quot;*&quot; Comment : 发表
    Article &quot;1&quot; -- &quot;*&quot; Comment : 拥有
    Article &quot;1&quot; -- &quot;*&quot; Category : 属于
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;状态图示例&lt;/h2&gt;
&lt;p&gt;状态图显示对象在其生命周期中经历的状态序列。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;stateDiagram-v2
    [*] --&amp;gt; 草稿
    
    草稿 --&amp;gt; 审核中 : 提交
    审核中 --&amp;gt; 草稿 : 拒绝
    审核中 --&amp;gt; 已批准 : 批准
    已批准 --&amp;gt; 已发布 : 发布
    已发布 --&amp;gt; 已归档 : 归档
    已发布 --&amp;gt; 草稿 : 撤回
    
    state 已发布 {
        [*] --&amp;gt; 活跃
        活跃 --&amp;gt; 隐藏 : 临时隐藏
        隐藏 --&amp;gt; 活跃 : 恢复
        活跃 --&amp;gt; [*]
        隐藏 --&amp;gt; [*]
    }
    
    已归档 --&amp;gt; [*]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;饼图示例&lt;/h2&gt;
&lt;p&gt;饼图非常适合显示比例和百分比数据。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pie title 网站流量来源分析
    &quot;搜索引擎&quot; : 45.6
    &quot;直接访问&quot; : 30.1
    &quot;社交媒体&quot; : 15.3
    &quot;推荐链接&quot; : 6.4
    &quot;其他来源&quot; : 2.6
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;Mermaid 是在 Markdown 文档中创建各种类型图表的强大工具。本文演示了如何使用流程图、时序图、甘特图、类图、状态图和饼图。这些图表可以帮助您更清晰地表达复杂的概念、流程和数据结构。&lt;/p&gt;
&lt;p&gt;要使用 Mermaid，只需在代码块中指定 mermaid 语言，并使用简洁的文本语法描述图表。Mermaid 会自动将这些描述转换为美观的可视化图表。&lt;/p&gt;
&lt;p&gt;尝试在您的下一篇技术博客文章或项目文档中使用 Mermaid 图表 - 它们将使您的内容更加专业且更易理解！&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>MDX 格式文章示例</title><link>https://blog.ithuo.net/posts/mdx-example/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/mdx-example/</guid><description>这是一个 MDX 格式的示例文章，展示了如何在 Markdown 中使用 JSX。</description><pubDate>Wed, 01 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import { Icon } from &apos;astro-icon/components&apos;&lt;/p&gt;
&lt;p&gt;:::tip
&lt;a href=&quot;https://github.com/CuteLeaf/Firefly&quot;&gt;Firefly&lt;/a&gt; 支持 &lt;code&gt;MDX&lt;/code&gt; 和 &lt;code&gt;Markdown&lt;/code&gt; 两种类型的文章，你可以在文章中混合使用两种格式，如果没有特别复杂内容和需求，推荐使用 Markdown 格式就够了。
:::&lt;/p&gt;
&lt;h2&gt;Markdown 和 MDX 的区别&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Markdown (MD) 是一种轻量级标记语言，允许用户使用纯文本格式编写文档，然后将其转换为格式化的HTML。它因其简洁易用的语法而广受欢迎，特别适合编写文档和博客文章。&lt;/li&gt;
&lt;li&gt;MDX 是一种扩展了 Markdown 语法的格式，允许在 Markdown 文档中无缝地插入 JSX 代码。通过 MDX，用户可以在文档中嵌入 React 组件，从而实现更丰富的交互性和动态性。&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;Markdown&lt;/th&gt;
&lt;th&gt;MDX&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;基础语法&lt;/td&gt;
&lt;td&gt;支持 (CommonMark)&lt;/td&gt;
&lt;td&gt;支持 (CommonMark)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTML 标签&lt;/td&gt;
&lt;td&gt;支持&lt;/td&gt;
&lt;td&gt;支持 (作为 JSX)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;组件导入&lt;/td&gt;
&lt;td&gt;不支持&lt;/td&gt;
&lt;td&gt;支持 (import)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;动态数据&lt;/td&gt;
&lt;td&gt;不支持&lt;/td&gt;
&lt;td&gt;支持 (JS 表达式)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;样式定制&lt;/td&gt;
&lt;td&gt;有限 (class/style)&lt;/td&gt;
&lt;td&gt;灵活 (className/CSS-in-JS)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;使用组件&lt;/h2&gt;
&lt;p&gt;这是一个图标组件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { Icon } from &apos;astro-icon/components&apos;

&amp;lt;div class=&quot;flex items-center gap-2 my-4&quot;&amp;gt;
  &amp;lt;Icon name=&quot;fa6-solid:rocket&quot; class=&quot;text-4xl text-red-500&quot; /&amp;gt;
  &amp;lt;span&amp;gt;火箭发射！&amp;lt;/span&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;div class=&quot;flex items-center gap-2 my-4&quot;&amp;gt;
&amp;lt;Icon name=&quot;fa6-solid:rocket&quot; class=&quot;text-4xl text-red-500&quot; /&amp;gt;
&amp;lt;span&amp;gt;火箭发射！&amp;lt;/span&amp;gt;
&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;h2&gt;使用 JSX&lt;/h2&gt;
&lt;p&gt;你也可以直接写 HTML/JSX：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div className=&quot;p-4 bg-blue-100 dark:bg-blue-900 rounded-lg my-4&quot;&amp;gt;
  这是一个自定义样式的 div 块，使用了 Tailwind CSS 类。
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;div className=&quot;p-4 bg-blue-100 dark:bg-blue-900 rounded-lg my-4&quot;&amp;gt;
这是一个自定义样式的 div 块，使用了 Tailwind CSS 类。
&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;h2&gt;简单的变量导出&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;export const year = new Date().getFullYear()

今年是 {year} 年。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;export const year = new Date().getFullYear()&lt;/p&gt;
&lt;p&gt;今年是 {year} 年。&lt;/p&gt;
&lt;p&gt;更多信息，请查看 &lt;a href=&quot;https://mdxjs.com/&quot;&gt;MDX 文档&lt;/a&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>在文章中嵌入视频</title><link>https://blog.ithuo.net/posts/video/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/video/</guid><description>这篇文章演示如何在博客文章中嵌入视频。</description><pubDate>Wed, 01 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;只需从 YouTube 或其他平台复制嵌入代码，然后将其粘贴到 markdown 文件中。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---
title: 在文章中嵌入视频
published: 2023-10-19
// ...
---

&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;https://www.youtube.com/embed/5gIf0_xpFPI?si=N1WTorLKL0uwLsU_&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;YouTube&lt;/h2&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;https://www.youtube.com/embed/5gIf0_xpFPI?si=N1WTorLKL0uwLsU_&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;h2&gt;Bilibili&lt;/h2&gt;
&lt;p&gt;&amp;lt;iframe width=&quot;100%&quot; height=&quot;468&quot; src=&quot;//player.bilibili.com/player.html?bvid=BV1fK4y1s7Qf&amp;amp;p=1&amp;amp;autoplay=0&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; &amp;amp;autoplay=0&amp;gt; &amp;lt;/iframe&amp;gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>Markdown 扩展功能</title><link>https://blog.ithuo.net/posts/markdown-extended/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/markdown-extended/</guid><description>了解 Firefly 中的 Markdown 功能</description><pubDate>Wed, 01 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;GitHub 仓库卡片&lt;/h2&gt;
&lt;p&gt;您可以添加链接到 GitHub 仓库的动态卡片，在页面加载时，仓库信息会从 GitHub API 获取。&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;CuteLeaf/Firefly&quot;}&lt;/p&gt;
&lt;p&gt;使用代码 &lt;code&gt;::github{repo=&quot;CuteLeaf/Firefly&quot;}&lt;/code&gt; 创建 GitHub 仓库卡片。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;::github{repo=&quot;CuteLeaf/Firefly&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;提醒框&lt;/h2&gt;
&lt;p&gt;支持以下类型的提醒框：&lt;code&gt;note&lt;/code&gt; &lt;code&gt;tip&lt;/code&gt; &lt;code&gt;important&lt;/code&gt; &lt;code&gt;warning&lt;/code&gt; &lt;code&gt;caution&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;:::note
突出显示用户应该考虑的信息，即使在快速浏览时也是如此。
:::&lt;/p&gt;
&lt;p&gt;:::tip
可选信息，帮助用户更成功。
:::&lt;/p&gt;
&lt;p&gt;:::important
用户成功所必需的关键信息。
:::&lt;/p&gt;
&lt;p&gt;:::warning
由于潜在风险需要用户立即注意的关键内容。
:::&lt;/p&gt;
&lt;p&gt;:::caution
行动的负面潜在后果。
:::&lt;/p&gt;
&lt;h3&gt;基本语法&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;:::note
突出显示用户应该考虑的信息，即使在快速浏览时也是如此。
:::

:::tip
可选信息，帮助用户更成功。
:::
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;自定义标题&lt;/h3&gt;
&lt;p&gt;可以自定义提醒框的标题。&lt;/p&gt;
&lt;p&gt;:::note[我的自定义标题]
这是一个带有自定义标题的注释。
:::&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:::note[我的自定义标题]
这是一个带有自定义标题的注释。
:::
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;GitHub 语法&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;[!TIP]
也支持 &lt;a href=&quot;https://github.com/orgs/community/discussions/16925&quot;&gt;GitHub 语法&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; [!NOTE]
&amp;gt; 也支持 GitHub 语法。

&amp;gt; [!TIP]
&amp;gt; 也支持 GitHub 语法。
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;剧透&lt;/h3&gt;
&lt;p&gt;您可以为文本添加剧透。文本也支持 &lt;strong&gt;Markdown&lt;/strong&gt; 语法。&lt;/p&gt;
&lt;p&gt;内容 :spoiler[被隐藏了 &lt;strong&gt;哈哈&lt;/strong&gt;]！&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;内容 :spoiler[被隐藏了 **哈哈**]！&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>Derick</author></item><item><title>Markdown 教程</title><link>https://blog.ithuo.net/posts/markdown-tutorial/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/markdown-tutorial/</guid><description>一个简明的 Markdown 博客示例。</description><pubDate>Wed, 01 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;这是一个展示如何编写 Markdown 文件的示例。本文档汇总了核心语法与常见扩展（GFM）。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#block-elements&quot;&gt;块级元素&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#paragraphs-and-line-breaks&quot;&gt;段落与换行&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#headers&quot;&gt;标题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#blockquotes&quot;&gt;引用&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#lists&quot;&gt;列表&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#code-blocks&quot;&gt;代码块&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#horizontal-rules&quot;&gt;分割线&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#table&quot;&gt;表格&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#span-elements&quot;&gt;内联元素&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#links&quot;&gt;链接&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#emphasis&quot;&gt;强调&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#code&quot;&gt;行内代码&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#images&quot;&gt;图片&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#strikethrough&quot;&gt;删除线&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#miscellaneous&quot;&gt;杂项&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#automatic-links&quot;&gt;自动链接&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#backslash-escapes&quot;&gt;反斜杠转义&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#inline-html&quot;&gt;内联 HTML&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;a id=&quot;block-elements&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;h2&gt;块级元素&lt;/h2&gt;
&lt;p&gt;&amp;lt;a id=&quot;paragraphs-and-line-breaks&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;h3&gt;段落与换行&lt;/h3&gt;
&lt;h4&gt;段落&lt;/h4&gt;
&lt;p&gt;HTML 标签：&lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;使用一个或多个空行分隔段落。（仅包含&lt;strong&gt;空格&lt;/strong&gt;或&lt;strong&gt;制表符&lt;/strong&gt;的行也视为空行。）&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;This will be
inline.

This is second paragraph.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This will be
inline.&lt;/p&gt;
&lt;p&gt;This is second paragraph.&lt;/p&gt;
&lt;hr /&gt;
&lt;h4&gt;换行&lt;/h4&gt;
&lt;p&gt;HTML 标签：&lt;code&gt;&amp;lt;br /&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;在行末添加&lt;strong&gt;两个或更多空格&lt;/strong&gt;来产生换行。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;This will be not
inline.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This will be not&lt;br /&gt;
inline.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;a id=&quot;headers&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;h3&gt;标题&lt;/h3&gt;
&lt;p&gt;Markdown 支持两种标题样式：Setext 与 atx。&lt;/p&gt;
&lt;h4&gt;Setext&lt;/h4&gt;
&lt;p&gt;HTML 标签：&lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;，&lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;使用&lt;strong&gt;等号 (=)&lt;/strong&gt; 表示 &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;、使用&lt;strong&gt;短横线 (-)&lt;/strong&gt; 表示 &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;，数量不限，作为“下划线”。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;This is an H1
=============
This is an H2
-------------
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;This is an H1&lt;/h1&gt;
&lt;h2&gt;This is an H2&lt;/h2&gt;
&lt;hr /&gt;
&lt;h4&gt;atx&lt;/h4&gt;
&lt;p&gt;HTML 标签：&lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;，&lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;，&lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt;，&lt;code&gt;&amp;lt;h4&amp;gt;&lt;/code&gt;，&lt;code&gt;&amp;lt;h5&amp;gt;&lt;/code&gt;，&lt;code&gt;&amp;lt;h6&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;在行首使用 1-6 个&lt;strong&gt;井号 (#)&lt;/strong&gt;，对应 &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; 至 &lt;code&gt;&amp;lt;h6&amp;gt;&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# This is an H1
## This is an H2
###### This is an H6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;This is an H1&lt;/h1&gt;
&lt;h2&gt;This is an H2&lt;/h2&gt;
&lt;h6&gt;This is an H6&lt;/h6&gt;
&lt;hr /&gt;
&lt;p&gt;可选：你可以在行尾“闭合” atx 标题。末尾的井号数量&lt;strong&gt;不必与&lt;/strong&gt;开头一致。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# This is an H1 #
## This is an H2 ##
### This is an H3 ######
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;This is an H1&lt;/h1&gt;
&lt;h2&gt;This is an H2&lt;/h2&gt;
&lt;h3&gt;This is an H3&lt;/h3&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;a id=&quot;blockquotes&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;h3&gt;引用&lt;/h3&gt;
&lt;p&gt;HTML 标签：&lt;code&gt;&amp;lt;blockquote&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Markdown 使用邮件风格的 &lt;strong&gt;&amp;gt;&lt;/strong&gt; 作为引用符号。若手动换行并在每行前加 &amp;gt;，显示效果最佳。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
&amp;gt; consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
&amp;gt; Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
&amp;gt;
&amp;gt; Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
&amp;gt; id sem consectetuer libero luctus adipiscing.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.&lt;/p&gt;
&lt;p&gt;Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
id sem consectetuer libero luctus adipiscing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;Markdown 允许“偷懒”：在一个硬换行段落中，只在第一行前加 &amp;gt; 即可。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.

&amp;gt; Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
id sem consectetuer libero luctus adipiscing.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
id sem consectetuer libero luctus adipiscing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;引用可以嵌套（引用中的引用），通过增加 &amp;gt; 层级实现。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; This is the first level of quoting.
&amp;gt;
&amp;gt; &amp;gt; This is nested blockquote.
&amp;gt;
&amp;gt; Back to the first level.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;p&gt;This is the first level of quoting.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is nested blockquote.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Back to the first level.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;引用内可包含其他 Markdown 元素，包括标题、列表与代码块。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; ## This is a header.
&amp;gt;
&amp;gt; 1.   This is the first list item.
&amp;gt; 2.   This is the second list item.
&amp;gt;
&amp;gt; Here&apos;s some example code:
&amp;gt;
&amp;gt;     return shell_exec(&quot;echo $input | $markdown_script&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;h2&gt;This is a header.&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;This is the first list item.&lt;/li&gt;
&lt;li&gt;This is the second list item.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here&apos;s some example code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;return shell_exec(&quot;echo $input | $markdown_script&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;a id=&quot;lists&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;h3&gt;列表&lt;/h3&gt;
&lt;p&gt;Markdown 支持有序（数字）与无序（圆点）列表。&lt;/p&gt;
&lt;h4&gt;无序列表&lt;/h4&gt;
&lt;p&gt;HTML 标签：&lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;无序列表可使用 &lt;strong&gt;星号 (*)&lt;/strong&gt;、&lt;strong&gt;加号 (+)&lt;/strong&gt; 或 &lt;strong&gt;短横线 (-)&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;*   Red
*   Green
*   Blue
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;Red&lt;/li&gt;
&lt;li&gt;Green&lt;/li&gt;
&lt;li&gt;Blue&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;等价于：&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;+   Red
+   Green
+   Blue
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-   Red
-   Green
-   Blue
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;有序列表&lt;/h4&gt;
&lt;p&gt;HTML 标签：&lt;code&gt;&amp;lt;ol&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;有序列表使用数字加英文句点：&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1.  Bird
2.  McHale
3.  Parish
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li&gt;Bird&lt;/li&gt;
&lt;li&gt;McHale&lt;/li&gt;
&lt;li&gt;Parish&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;p&gt;注意：像下面这样可能会“意外触发”有序列表：&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1986. What a great season.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li&gt;What a great season.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;p&gt;你可以用&lt;strong&gt;反斜杠转义 (\)&lt;/strong&gt; 句点：&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1986\. What a great season.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;1986. What a great season.&lt;/p&gt;
&lt;hr /&gt;
&lt;h4&gt;列表中的缩进内容&lt;/h4&gt;
&lt;h5&gt;列表项里的引用&lt;/h5&gt;
&lt;p&gt;在列表项内放置引用，需要将 &amp;gt; 符号整体缩进：&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;*   A list item with a blockquote:

    &amp;gt; This is a blockquote
    &amp;gt; inside a list item.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A list item with a blockquote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a blockquote
inside a list item.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h5&gt;列表项里的代码块&lt;/h5&gt;
&lt;p&gt;在列表项内放置代码块，需要缩进两层——&lt;strong&gt;8 个空格&lt;/strong&gt;或&lt;strong&gt;两个 Tab&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;*   A list item with a code block:

        &amp;lt;code goes here&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A list item with a code block:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;code goes here&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h5&gt;嵌套列表&lt;/h5&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;* A
  * A1
  * A2
* B
* C
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;A
&lt;ul&gt;
&lt;li&gt;A1&lt;/li&gt;
&lt;li&gt;A2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;B&lt;/li&gt;
&lt;li&gt;C&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;a id=&quot;code-blocks&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;h3&gt;代码块&lt;/h3&gt;
&lt;p&gt;HTML 标签：&lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;将代码块中的每行缩进至少&lt;strong&gt;4 个空格&lt;/strong&gt;或&lt;strong&gt;1 个制表符&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;This is a normal paragraph:

    This is a code block.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This is a normal paragraph:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;This is a code block.
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;p&gt;代码块会一直持续，直到遇到未缩进的行（或文末）。&lt;/p&gt;
&lt;p&gt;在代码块内，&lt;strong&gt;与号 (&amp;amp;)&lt;/strong&gt; 和尖括号 &lt;strong&gt;(&amp;lt; &amp;gt;)&lt;/strong&gt; 会自动转为 HTML 实体。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    &amp;lt;div class=&quot;footer&quot;&amp;gt;
        &amp;amp;copy; 2004 Foo Corporation
    &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;footer&quot;&amp;gt;
    &amp;amp;copy; 2004 Foo Corporation
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;p&gt;下文的“围栏代码块”和“语法高亮”属于扩展语法，你也可以用它们来书写代码块。&lt;/p&gt;
&lt;h4&gt;围栏代码块&lt;/h4&gt;
&lt;p&gt;使用成对的反引号围起来（如下所示），就不需要四空格缩进了。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Here&apos;s an example:

```
function test() {
  console.log(&quot;notice the blank line before this function?&quot;);
}
```
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Here&apos;s an example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function test() {
  console.log(&quot;notice the blank line before this function?&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h4&gt;语法高亮&lt;/h4&gt;
&lt;p&gt;在围栏代码块后添加可选的语言标识，即可启用语法高亮（参见支持语言列表）。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;```ruby
require &apos;redcarpet&apos;
markdown = Redcarpet.new(&quot;Hello World!&quot;)
puts markdown.to_html
```
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code&gt;require &apos;redcarpet&apos;
markdown = Redcarpet.new(&quot;Hello World!&quot;)
puts markdown.to_html
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;a id=&quot;horizontal-rules&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;h3&gt;分割线（水平线）&lt;/h3&gt;
&lt;p&gt;HTML 标签：&lt;code&gt;&amp;lt;hr /&amp;gt;&lt;/code&gt;
一行中放置&lt;strong&gt;三个或以上的短横线 (-)、星号 (*) 或下划线 (_)&lt;/strong&gt;。符号之间允许有空格。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;* * *
***
*****
- - -
---------------------------------------
___
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;hr /&gt;
&lt;hr /&gt;
&lt;hr /&gt;
&lt;hr /&gt;
&lt;hr /&gt;
&lt;hr /&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;a id=&quot;table&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;h3&gt;表格&lt;/h3&gt;
&lt;p&gt;HTML 标签：&lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这是扩展语法。&lt;/p&gt;
&lt;p&gt;用&lt;strong&gt;竖线 (|)&lt;/strong&gt; 分隔列，用&lt;strong&gt;短横线 (-)&lt;/strong&gt; 分隔表头，使用&lt;strong&gt;冒号 (:)&lt;/strong&gt; 指定对齐方式。&lt;/p&gt;
&lt;p&gt;两侧的&lt;strong&gt;竖线 (|)&lt;/strong&gt; 与对齐可选。用于表头分隔时，每列至少需要 &lt;strong&gt;3 个短横线&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;| Left | Center | Right |
|:-----|:------:|------:|
|aaa   |bbb     |ccc    |
|ddd   |eee     |fff    |

 A | B
---|---
123|456


A |B
--|--
12|45
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Left&lt;/th&gt;
&lt;th&gt;Center&lt;/th&gt;
&lt;th&gt;Right&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;aaa&lt;/td&gt;
&lt;td&gt;bbb&lt;/td&gt;
&lt;td&gt;ccc&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ddd&lt;/td&gt;
&lt;td&gt;eee&lt;/td&gt;
&lt;td&gt;fff&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;A&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;123&lt;/td&gt;
&lt;td&gt;456&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;A&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;45&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;a id=&quot;span-elements&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;h2&gt;内联元素&lt;/h2&gt;
&lt;p&gt;&amp;lt;a id=&quot;links&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;h3&gt;链接&lt;/h3&gt;
&lt;p&gt;HTML 标签：&lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Markdown 支持两种链接样式：行内链接与引用式链接。&lt;/p&gt;
&lt;h4&gt;行内链接&lt;/h4&gt;
&lt;p&gt;行内链接格式：&lt;code&gt;[文本](URL &quot;标题&quot;)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;标题可选。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;This is [an example](http://example.com/ &quot;Title&quot;) inline link.

[This link](http://example.net/) has no title attribute.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This is &lt;a href=&quot;http://example.com/&quot;&gt;an example&lt;/a&gt; inline link.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://example.net/&quot;&gt;This link&lt;/a&gt; has no title attribute.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;如果引用同一站点的本地资源，可以使用相对路径：&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;See my [About](/about/) page for details.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;See my &lt;a href=&quot;/about/&quot;&gt;About&lt;/a&gt; page for details.&lt;/p&gt;
&lt;hr /&gt;
&lt;h4&gt;引用式链接&lt;/h4&gt;
&lt;p&gt;可以预定义链接引用。定义格式：&lt;code&gt;[id]: URL &quot;标题&quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;标题同样可选。引用时使用：&lt;code&gt;[文本][id]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[id]: http://example.com/  &quot;Optional Title Here&quot;
This is [an example][id] reference-style link.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This is &lt;a href=&quot;http://example.com/&quot;&gt;an example&lt;/a&gt; reference-style link.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;方括号中包含链接标识（&lt;strong&gt;不区分大小写&lt;/strong&gt;，可在左侧缩进最多三格空格）；&lt;/li&gt;
&lt;li&gt;随后是冒号；&lt;/li&gt;
&lt;li&gt;再跟一个或多个空格（或 tab）；&lt;/li&gt;
&lt;li&gt;然后是链接 URL；&lt;/li&gt;
&lt;li&gt;URL 可选地用尖括号包裹；&lt;/li&gt;
&lt;li&gt;可选地跟随标题属性，用引号或圆括号包裹。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以下三种定义等价：&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[foo]: http://example.com/  &quot;Optional Title Here&quot;
[foo]: http://example.com/  &apos;Optional Title Here&apos;
[foo]: http://example.com/  (Optional Title Here)
[foo]: &amp;lt;http://example.com/&amp;gt;  &quot;Optional Title Here&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果使用空的方括号，则链接文本本身会作为名称。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Google]: http://google.com/
[Google][]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href=&quot;http://google.com/&quot;&gt;Google&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;a id=&quot;emphasis&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;h3&gt;强调&lt;/h3&gt;
&lt;p&gt;HTML 标签：&lt;code&gt;&amp;lt;em&amp;gt;&lt;/code&gt;，&lt;code&gt;&amp;lt;strong&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Markdown 使用 &lt;strong&gt;星号 (*)&lt;/strong&gt; 或 &lt;strong&gt;下划线 (_)&lt;/strong&gt; 表示强调。&lt;strong&gt;一个分隔符&lt;/strong&gt;对应 &lt;code&gt;&amp;lt;em&amp;gt;&lt;/code&gt;；&lt;strong&gt;两个分隔符&lt;/strong&gt;对应 &lt;code&gt;&amp;lt;strong&amp;gt;&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;*single asterisks*

_single underscores_

**double asterisks**

__double underscores__
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;single asterisks&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;single underscores&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;double asterisks&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;double underscores&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;但如果两侧有空格，则会被视作普通字符而非强调语法。&lt;/p&gt;
&lt;p&gt;你可以使用反斜杠进行转义：&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;\*this text is surrounded by literal asterisks\*
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;*this text is surrounded by literal asterisks*&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;a id=&quot;code&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;h3&gt;行内代码&lt;/h3&gt;
&lt;p&gt;HTML 标签：&lt;code&gt;&amp;lt;code&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;用&lt;strong&gt;反引号 (`)&lt;/strong&gt; 包裹。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Use the `printf()` function.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Use the &lt;code&gt;printf()&lt;/code&gt; function.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;若行内代码中需要包含反引号字符，可使用&lt;strong&gt;多重反引号&lt;/strong&gt;作为定界符：&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;``There is a literal backtick (`) here.``
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;code&gt;There is a literal backtick (`) here.&lt;/code&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;行内代码两侧的定界符允许包含空格（开头一个、结尾一个），方便在代码起始或结尾放置反引号字符：&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A single backtick in a code span: `` ` ``

A backtick-delimited string in a code span: `` `foo` ``
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;A single backtick in a code span: &lt;code&gt;`&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;A backtick-delimited string in a code span: &lt;code&gt;`foo`&lt;/code&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;a id=&quot;images&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;h3&gt;图片&lt;/h3&gt;
&lt;p&gt;HTML 标签：&lt;code&gt;&amp;lt;img /&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Markdown 的图片语法与链接类似，支持行内与引用两种方式。&lt;/p&gt;
&lt;h4&gt;行内图片&lt;/h4&gt;
&lt;p&gt;行内图片语法：&lt;code&gt;![替代文本](URL &quot;标题&quot;)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;标题可选。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;![Alt text](/path/to/img.jpg)

![Alt text](/path/to/img.jpg &quot;Optional title&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;img src=&quot;https://s2.loli.net/2024/08/20/5fszgXeOxmL3Wdv.webp&quot; alt=&quot;Alt text&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://s2.loli.net/2024/08/20/5fszgXeOxmL3Wdv.webp&quot; alt=&quot;Alt text&quot; title=&quot;Optional title&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个感叹号 !；&lt;/li&gt;
&lt;li&gt;后接方括号，放置图片的替代文本；&lt;/li&gt;
&lt;li&gt;再接圆括号，内含图片 URL/路径，及可选的标题（引号包裹）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;引用式图片&lt;/h4&gt;
&lt;p&gt;引用式图片语法：&lt;code&gt;![替代文本][id]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[img id]: https://s2.loli.net/2024/08/20/5fszgXeOxmL3Wdv.webp  &quot;Optional title attribute&quot;
![Alt text][img id]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;img src=&quot;https://s2.loli.net/2024/08/20/5fszgXeOxmL3Wdv.webp&quot; alt=&quot;Alt text&quot; title=&quot;Optional title attribute&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;a id=&quot;strikethrough&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;h3&gt;删除线&lt;/h3&gt;
&lt;p&gt;HTML 标签：&lt;code&gt;&amp;lt;del&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这是扩展语法。&lt;/p&gt;
&lt;p&gt;GFM 增加了删除线语法。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~~Mistaken text.~~
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;s&gt;Mistaken text.&lt;/s&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;a id=&quot;miscellaneous&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;h2&gt;杂项&lt;/h2&gt;
&lt;p&gt;&amp;lt;a id=&quot;automatic-links&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;h3&gt;自动链接&lt;/h3&gt;
&lt;p&gt;Markdown 支持一种便捷写法来创建“自动链接”（URL 与邮箱地址）：只需用尖括号将其包住即可。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;http://example.com/&amp;gt;

&amp;lt;address@example.com&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href=&quot;http://example.com/&quot;&gt;http://example.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;mailto:address@example.com&quot;&gt;address@example.com&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;GFM 会自动识别标准 URL 并转换为链接。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://github.com/emn178/markdown
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;https://github.com/emn178/markdown&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;a id=&quot;backslash-escapes&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;h3&gt;反斜杠转义&lt;/h3&gt;
&lt;p&gt;Markdown 允许使用反斜杠来转义那些本用于 Markdown 语法的特殊字符，使其按字面显示。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;\*literal asterisks\*
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;*literal asterisks*&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;以下字符可通过反斜杠转义以按字面量输出：&lt;/p&gt;
&lt;p&gt;Code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;\   backslash
`   backtick
*   asterisk
_   underscore
{}  curly braces
[]  square brackets
()  parentheses
#   hash mark
+   plus sign
-   minus sign (hyphen)
.   dot
!   exclamation mark
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;a id=&quot;inline-html&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;h2&gt;内联 HTML&lt;/h2&gt;
&lt;p&gt;对于 Markdown 语法未覆盖的标记，直接使用原生 HTML 即可。无需特别声明从 Markdown 切换到 HTML，直接写标签就行。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;This is a regular paragraph.

&amp;lt;table&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td&amp;gt;Foo&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;

This is another regular paragraph.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This is a regular paragraph.&lt;/p&gt;
&lt;p&gt;&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td&amp;gt;Foo&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;&lt;/p&gt;
&lt;p&gt;This is another regular paragraph.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;请注意：在&lt;strong&gt;块级 HTML 标签&lt;/strong&gt;内不会处理 Markdown 语法。&lt;/p&gt;
&lt;p&gt;与块级标签不同，在&lt;strong&gt;行内级标签&lt;/strong&gt;内会处理 Markdown 语法。&lt;/p&gt;
&lt;p&gt;代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;span&amp;gt;**Work**&amp;lt;/span&amp;gt;

&amp;lt;div&amp;gt;
    **No Work**
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预览：&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;span&amp;gt;&lt;strong&gt;Work&lt;/strong&gt;&amp;lt;/span&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;div&amp;gt;
&lt;strong&gt;No Work&lt;/strong&gt;
&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
</content:encoded><author>emn178</author></item><item><title>NodeJS初始化配置</title><link>https://blog.ithuo.net/posts/nodejs-initial-configuration/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/nodejs-initial-configuration/</guid><pubDate>Sat, 16 Nov 2019 00:00:00 GMT</pubDate><content:encoded>&lt;pre&gt;&lt;code&gt;目录
1. 背景
2. npm
  2.1. 配置镜像源
  2.2. 配置代理
3. yarn
  3.1. 配置镜像源
  3.2. 配置代理
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;strong&gt;1. 背景&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;众所周知在国内下载npm会很慢，并且阶段性的无法访问，所以需要换npm、yarn的镜像源，或配置npm、yarn的代理，都是为了解决 npm 依赖下载慢的问题。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;如果你要下载的依赖，都能在“淘宝”或者“cnpm”镜像源上找到，那么就能加速很多。&lt;/p&gt;
&lt;p&gt;&amp;lt;u&amp;gt;&lt;em&gt;&lt;strong&gt;换镜像源&lt;/strong&gt;&lt;/em&gt;&amp;lt;/u&amp;gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果你必须通过“npm镜像源”下载依赖（例如：你依赖的某特定版本的库，淘宝、cnpm镜像源上还没来得及与 npm 镜像源同步），那么你就需要&amp;lt;u&amp;gt;&lt;em&gt;&lt;strong&gt;配置代理&lt;/strong&gt;&lt;/em&gt;&amp;lt;/u&amp;gt;，&amp;lt;u&amp;gt;&lt;em&gt;&lt;strong&gt;科学上网&lt;/strong&gt;&lt;/em&gt;&amp;lt;/u&amp;gt;（如果你有&lt;a href=&quot;https://cloud.tencent.com/product/vpn?from_column=20065&amp;amp;from=20065&quot;&gt;VPN&lt;/a&gt;，那更省事）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;2. npm&lt;/strong&gt;&lt;/h3&gt;
&lt;h4&gt;&amp;lt;u&amp;gt;&lt;strong&gt;2.1. 配置镜像源&lt;/strong&gt;&amp;lt;/u&amp;gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;方式1：npm 命令&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// 查看镜像源
npm config get registry

// 设置镜像源
npm config set registry http://registry.npmmirror.com/
npm config set registry https://registry.npmjs.org/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/f6168e5ad1d043ca4bdba5c52d37a69c.png&quot; alt=&quot;kr9swdjcl6.png&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;方式2：nrm 工具&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;nrm can help you easy and fast switch between different npm registries, now include: npm, cnpm, taobao, nj(nodejitsu).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;npm install -g nrm // 安装
nrm ls // 查看已有的源
nrm use &amp;lt;registry&amp;gt; // 切换源
nrm add &amp;lt;registry&amp;gt; &amp;lt;url&amp;gt; // 添加源
nrm del &amp;lt;registry&amp;gt; // 删除源
nrm test [registry] // 测速
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/0017b48b83a3822404228232b76490ee.png&quot; alt=&quot;5ufngnd8h5.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/33177e82239727fd8b018dd2032308a3.png&quot; alt=&quot;rwryrg9jqn.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;u&amp;gt;&lt;strong&gt;2.2. 配置代理&lt;/strong&gt;&amp;lt;/u&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 查看代理
npm config get proxy
npm config get https-proxy

// 设置代理
npm config set proxy http://127.0.0.1:8080
npm config set https-proxy http://127.0.0.1:8080

// 删除代理
npm config delete proxy
npm config delete https-proxy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;3. yarn&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;u&amp;gt;&lt;strong&gt;3.1. 配置镜像源&lt;/strong&gt;&amp;lt;/u&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 查看镜像源
yarn config get registry

// 设置镜像源
yarn config set registry http://registry.npm.taobao.org/
yarn config set registry https://registry.npmjs.org/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;u&amp;gt;&lt;strong&gt;3.2. 配置代理&lt;/strong&gt;&amp;lt;/u&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 查看代理
yarn config get proxy
yarn config get https-proxy

// 设置代理
yarn config set proxy http://127.0.0.1:8080
yarn config set https-proxy http://127.0.0.1:8080

// 删除代理
yarn config delete proxy
yarn config delete https-proxy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;参考：&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;NPM registry manager（nrm）：&lt;br /&gt;
https://github.com/Pana/nrm&lt;/p&gt;
&lt;p&gt;npm Docs：&lt;br /&gt;
https://docs.npmjs.com/cli/v6/using-npm/config#proxy&lt;/p&gt;
&lt;p&gt;https://docs.npmjs.com/cli/v6/using-npm/config#https-proxy&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded><author>Derick</author></item><item><title>如何避免前端内存泄漏</title><link>https://blog.ithuo.net/posts/how-to-avoid-frontend-memory-leak/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/how-to-avoid-frontend-memory-leak/</guid><pubDate>Tue, 12 Nov 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;随着应用程序变得更加复杂和强大，提高性能的需求也越来越大。为了帮助实现性能目标，工程团队已将注意力转向改善系统效率低下的问题，例如内存泄漏。&lt;/p&gt;
&lt;p&gt;垃圾收集是内存管理的重要组成部分。它是一个自动化过程，可识别并释放应用程序不再使用的内存。内存泄漏是由于内存分配管理不善造成的。当内存使用后没有正确释放时，就会发生泄漏，从而导致不必要的资源消耗。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/36d3f0592b0fae3185bcfe31c691f6e8.jpg&quot; alt=&quot;IMG_2815.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;前端内存泄漏会对 Web 应用程序的性能产生重大影响。它们可能会导致页面加载缓慢，占用不必要的内存，有时还会导致崩溃。在单页应用程序 (SPA) 中，它们可能是一个严重的问题，其中页面长时间保留在浏览器中，从而导致内存泄漏。&lt;/p&gt;
&lt;p&gt;内存泄漏可能由多种因素引起，但一些常见的原因包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;未清除的事件侦听器：事件侦听器附加到 DOM 中的元素，忘记删除这些侦听器会阻止元素被垃圾收集。这意味着该元素将继续消耗资源，即使它们不再是 DOM 的一部分。&lt;/li&gt;
&lt;li&gt;超出范围的引用：引用超出其范围的变量的闭包函数将这些变量保留在内存中。如果不清除对对象的引用，就会发生内存泄漏。&lt;/li&gt;
&lt;li&gt;长期变量：包含大对象的变量一旦不再需要就应该清除，以限制不必要的内存使用。&lt;/li&gt;
&lt;li&gt;延迟资源：打开外部资源的连接或流可能会导致大量的资源消耗。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;检测内存泄漏是一项艰巨的挑战。内存分析器等浏览器开发人员工具可以帮助识别最需要关注的区域。这些工具具有高级功能，可帮助进一步调查潜在的内存泄漏，例如捕获堆快照和详细的内存分配跟踪。&lt;/p&gt;
&lt;p&gt;应使用监控工具来跟踪趋势并识别内存使用量的峰值和性能下降。高级工具提供垃圾收集见解，让您了解垃圾收集器进程运行的频率以及每次释放多少内存。&lt;/p&gt;
&lt;p&gt;避免内存泄漏的最佳方法是设置阻止内存泄漏进入生产环境的流程。彻底的代码审查和测试是关键的防线。负载测试特别有用，因为在高负载水平期间内存泄漏往往变得更加明显。&lt;/p&gt;
&lt;p&gt;为了在代码审查期间有效地捕获内存泄漏，开发人员必须充分了解避免内存泄漏的最佳实践。&lt;/p&gt;
&lt;p&gt;以下是确保最佳内存使用并防止潜在问题的一些关键方法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一旦不再需要事件监听器就将其清除。&lt;/li&gt;
&lt;li&gt;避免全局变量。&lt;/li&gt;
&lt;li&gt;当不再使用外部资源的连接或流时，将其释放。&lt;/li&gt;
&lt;li&gt;清除大型数据结构并删除它们的引用。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;改进内存管理和内存泄漏监控可以带来更好、更可靠的 Web 应用程序，提供无缝的用户体验，同时最大限度地减少资源浪费。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>SOLID设计原则</title><link>https://blog.ithuo.net/posts/solid-design-principles/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/solid-design-principles/</guid><pubDate>Tue, 12 Nov 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;SOLID&lt;/strong&gt; 原则是**面向对象编程(OOP)**的关键. 但每项原则的实际含义是什么？它们为何如此重要？&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SOLID&lt;/strong&gt;代表**面向对象编程(OOP)**的五个原则。无论你是否使用OOP，知道这些原则都能让你深入了解干净代码的基础，这些代码可以应用于许多编程领域。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;𝗦 — 单一职责原则&lt;/li&gt;
&lt;li&gt;𝗢 — 对扩展开放，对修改关闭原则&lt;/li&gt;
&lt;li&gt;𝗟 — 里氏替换原则&lt;/li&gt;
&lt;li&gt;𝗜 — 接口隔离原则&lt;/li&gt;
&lt;li&gt;𝗗 — 依赖倒置原则&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面分析每个原则 ↓&lt;/p&gt;
&lt;p&gt;𝟭. 𝗦𝗶𝗻𝗴𝗹𝗲 𝗥𝗲𝘀𝗽𝗼𝗻𝘀𝗶𝗯𝗶𝗹𝗶𝘁𝘆 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲 (𝗦𝗥𝗣)&lt;/p&gt;
&lt;p&gt;每个代码单元应该只有一个工作或职责。单元可以是类、模块、函数或组件。这使代码保持模块化，并消除了紧密耦合的风险。&lt;/p&gt;
&lt;p&gt;𝟮. 𝗢𝗽𝗲𝗻-𝗖𝗹𝗼𝘀𝗲𝗱 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲 (𝗢𝗖𝗣)&lt;/p&gt;
&lt;p&gt;代码单元应该对扩展开放，但对修改关闭。您应该能够使用附加代码扩展功能，而不是修改现有代码。这个原则可以应用于基于组件的系统，比如React前端。&lt;/p&gt;
&lt;p&gt;𝟯. 𝗟𝗶𝘀𝗸𝗼𝘃 𝗦𝘂𝗯𝘀𝘁𝗶𝘁𝘂𝘁𝗶𝗼𝗻 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲 (𝗟𝗦𝗣)&lt;/p&gt;
&lt;p&gt;你应该能够用子类的基类替换它。换句话说，基类中的所有功能都应该被它的所有子类利用。如果不能，它就不应该在基类中。&lt;/p&gt;
&lt;p&gt;Bird基类就是一个例子。您可能会认为它应该有一个fly方法。但是那些不会飞的鸟呢?像企鹅一样。
在本例中，fly不应该在基类中，因为它并不适用于所有子类。&lt;/p&gt;
&lt;p&gt;𝟰. 𝗜𝗻𝘁𝗲𝗿𝗳𝗮𝗰𝗲 𝗦𝗲𝗴𝗿𝗲𝗴𝗮𝘁𝗶𝗼𝗻 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲 (𝗜𝗦𝗣)&lt;/p&gt;
&lt;p&gt;提供具有特定职责的多个接口，而不是一小组通用接口。客户端不需要知道与他们的用例无关的方法和属性。&lt;/p&gt;
&lt;p&gt;复杂性↓
代码灵活性↑&lt;/p&gt;
&lt;p&gt;𝟱. 𝗗𝗲𝗽𝗲𝗻𝗱𝗲𝗻𝗰𝘆 𝗜𝗻𝘃𝗲𝗿𝘀𝗶𝗼𝗻 𝗣𝗿𝗶𝗻𝗰𝗶𝗽𝗹𝗲 (𝗗𝗜𝗣)&lt;/p&gt;
&lt;p&gt;你应该依赖抽象类，而不是具体类。使用抽象来解耦系统不同部分之间的依赖关系。代码单元之间不应该直接调用，而应该使用接口或抽象&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/d4fd46b40bca271861cc0290580648ce.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>如何防止系统误用和资源过载？</title><link>https://blog.ithuo.net/posts/how-to-prevent-system-misuse-and-resource-overload/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/how-to-prevent-system-misuse-and-resource-overload/</guid><pubDate>Sun, 10 Nov 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;能够被大规模采用是任何系统或应用程序的梦想。但随之而来的是滥用和资源过载的风险。应采取措施确保所有用户的服务质量。&lt;/p&gt;
&lt;p&gt;上周，Twitter 就面临着这个问题。他们的解决方案？速率限制。这涉及限制用户或服务可以在系统上发出的请求数量。&lt;/p&gt;
&lt;p&gt;虽然对于许多情况来说这确实是一种可行的解决方案，但它并不是唯一的解决方案。让我们看一下可以在任何系统中实现的其他一些替代方案。值得注意的是，这些解决方案应以防御性方式实施，以避免出现需要临时补救措施的情况。&lt;/p&gt;
&lt;h1&gt;限流&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/ee7bcb8993f7f71fcf220ca259d8e6a4.jpg&quot; alt=&quot;IMG_2789.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;限流是一种简单的技术，可以减慢处理任务所需的时间，从而最大限度地减少资源消耗。这通常与配额或速率限制结合使用，这样用户就不会完全脱离服务，而是将服务质量降低到合理的水平。&lt;/p&gt;
&lt;p&gt;这是互联网服务提供商为最大程度地减少高峰流量期间的带宽拥塞而采取的流行方法。类似对服务器或 API 上的请求进行限制也通常在软件系统中完成。&lt;/p&gt;
&lt;h1&gt;认证与授权&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/3d40eb453af05b5abc5a620def12db30.jpg&quot; alt=&quot;IMG_2788.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这些都是重要的安全措施，可最大限度地降低服务误用和拒绝服务攻击 (DoS) 的风险。它还有助于识别和限制机器人和抓取帐户的访问。&lt;/p&gt;
&lt;p&gt;首先，将使用用户名和密码或更复杂的方法（例如 2FA）来验证和识别请求的用户或服务。一旦被识别，系统将确定请求者可以拥有哪些资源以及他们对系统资源的优先级（如果适用）。&lt;/p&gt;
&lt;h1&gt;验证码&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/64bbf68443a83503c9494a3dc80c1e52.jpg&quot; alt=&quot;IMG_2787.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;验证码旨在识别人类请求者并拒绝机器人的访问。它通过在授予服务或某些功能的访问权限之前引入人类可解决的测试来实现这一点。虽然这种技术是一种流行的方法，但它对应用程序可访问性的影响是一个值得注意的考虑因素。此外，人工智能技术使得区分人类请求者和机器人变得越来越困难。&lt;/p&gt;
&lt;h1&gt;入侵检测和预防系统&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/eebeadf02acf1eea368e88e974417eca.jpg&quot; alt=&quot;IMG_2786.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;此方法专门用于降低系统攻击的风险，包括监视网络流量以识别恶意活动。&lt;/p&gt;
&lt;p&gt;入侵检测系统 (IDS) 用于警告和报告已识别的威胁，而入侵防御系统 (IPS) 旨在阻止威胁。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;除了识别和阻止威胁的要求之外，防止系统过载的其他一些解决方案包括：&lt;/p&gt;
&lt;p&gt;🔸 负载均衡：将请求分布到多个服务器上。&lt;/p&gt;
&lt;p&gt;🔸 优先级：确保关键请求优先获得系统资源。&lt;/p&gt;
&lt;p&gt;🔸 断路器模式：防止可能失败的任务重试。&lt;/p&gt;
&lt;p&gt;🔸 并发限制：限制可以与系统建立的连接数或并发运行的任务数。&lt;/p&gt;
&lt;p&gt;防止系统过载和误用需要整个团队的努力来采用防御工程。应谨慎实施上述技术，以确保合法请求不受限制。应结合使用多种策略来开发适合您系统独特用例的全系统方法。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>事件驱动架构</title><link>https://blog.ithuo.net/posts/event-driven-architecture/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/event-driven-architecture/</guid><pubDate>Sat, 09 Nov 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;&lt;strong&gt;Understanding Event-Driven Systems&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;现代系统需要执行的很多任务都是为了响应状态的变化。&lt;/p&gt;
&lt;p&gt;将商品添加到购物车、点赞帖子和支付账单都是状态更改，会在各自的系统中触发一组任务。&lt;/p&gt;
&lt;p&gt;这一要求为流行的系统架构方法（称为事件驱动架构 (EDA)）铺平了道路。&lt;/p&gt;
&lt;p&gt;事件驱动架构中有四个主要组件——事件、生产者、消费者和通道。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/4ff7c14554cce371133fb3be6b5c3ef0.jpg&quot; alt=&quot;IMG_2761.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;事件是由生产者生成的系统状态的更新。当事件发生时，它会通过通道发送给消费者，然后触发操作或流程。&lt;/p&gt;
&lt;p&gt;事件可以同步或异步处理。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/29f6a5207a6158e9d5e0390488b4932d.jpg&quot; alt=&quot;IMG_2759.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;当使用同步方法时，生产者需要等待消费者处理事件，然后才能继续下一个任务。例如，在线预订酒店时，您的网络浏览器将等待系统完成您的请求并返回结果，然后才能继续。&lt;/p&gt;
&lt;p&gt;同步处理为每个给定事件提供了可预测的执行路径，这使得理解和调试变得更加简单。在立即响应至关重要的情况下（例如处理金融交易），这是必要的。然而，其刚性性质使其与生成大量事件或执行耗时处理操作的组件不兼容。同步处理限制了系统的可扩展性和容错能力，这就是为什么它只应在绝对必要时保留。&lt;/p&gt;
&lt;p&gt;另一方面，异步处理不等待响应。生产者将事件排队供消费者处理，然后继续执行下一个任务。例如，在社交媒体上发布状态更新不需要立即采取行动。相反，您的关注者可以收到异步通知。&lt;/p&gt;
&lt;p&gt;异步处理在事件驱动架构中更常用，因为它比同步方法更好地提高可扩展性、松散耦合、弹性和灵活性。它非常适合频繁且大量生成事件的场景，这通常是大多数使用事件驱动设计构建的系统的情况。竞争条件是异步处理最显着的陷阱，这通常最好通过精心设计的队列来解决。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;事件驱动架构是一种可扩展且高效的解决方案，适用于由许多节点或服务组成并处理大量事件的系统。它促进松散耦合，并有助于保持系统灵活且更易于维护。&lt;/p&gt;
</content:encoded><author>Derick</author></item><item><title>三分钟理解边缘计算与云计算</title><link>https://blog.ithuo.net/posts/understanding-edge-computing-and-cloud-computing-in-three-minutes/</link><guid isPermaLink="true">https://blog.ithuo.net/posts/understanding-edge-computing-and-cloud-computing-in-three-minutes/</guid><pubDate>Wed, 13 Mar 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;边缘计算与云计算——有什么区别？&lt;/p&gt;
&lt;p&gt;给我3分钟，我告诉你：&lt;/p&gt;
&lt;p&gt;在云计算中，计算和数据存储发生在集中位置，云服务提供商负责管理计算机资源。&lt;/p&gt;
&lt;p&gt;边缘计算是一种分布式数据存储和任务处理方法。通过将服务器放置在网络的“边缘”或实际设备上，它可以使计算更接近需要的地方。&lt;/p&gt;
&lt;p&gt;云计算相对于边缘计算的优势：&lt;/p&gt;
&lt;p&gt;🔹资源池可以具有成本效益。
🔹云服务提供商 (CSP) 拥有大量可用资源，这使得扩展或缩减变得简单。
🔹通信服务提供商为您管理所有基础设施，而边缘计算通常更复杂，因此更需要实践。
🔹云计算存在的时间较长，这意味着有更多的提供商和服务模型可供选择。&lt;/p&gt;
&lt;p&gt;边缘计算相对于云计算的优势：&lt;/p&gt;
&lt;p&gt;🔸通过在本地而不是在集中位置处理数据，可以减少延迟和带宽使用。
🔸可以实现实时数据处理。
🔸无需通过网络发送敏感数据可提高安全性。
🔸分布式系统降低了单个节点发生故障并导致整个系统瘫痪的可能性。&lt;/p&gt;
&lt;p&gt;边缘计算和云计算都是不错的选择，但哪一个最适合您取决于您的应用程序的要求。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://r2.ithuo.net/elog-image/4d801471f30b361d8977edc096d73884.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;/p&gt;
</content:encoded><author>Derick</author></item></channel></rss>