<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Posts on aiken&#39;s blog</title>
    <link>https://aikenh.cn/posts/</link>
    <description>Recent content in Posts on aiken&#39;s blog</description>
    <generator>Hugo -- 0.137.0</generator>
    <language>en-us</language>
    <lastBuildDate>Sun, 30 Mar 2025 14:16:22 +0000</lastBuildDate>
    <follow_challenge>
      <feedId>90080597450814464</feedId>
      <userId>72439538841050112</userId>
    </follow_challenge>
    <atom:link href="https://aikenh.cn/posts/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>使用 cloudflare 转发 ipv6 网页至 ipv4</title>
      <link>https://aikenh.cn/posts/%E4%BD%BF%E7%94%A8cloudflare%E8%BD%AC%E5%8F%91ipv6%E7%BD%91%E9%A1%B5%E8%87%B3ipv4/</link>
      <pubDate>Sun, 30 Mar 2025 14:16:22 +0000</pubDate>
      <guid>https://aikenh.cn/posts/%E4%BD%BF%E7%94%A8cloudflare%E8%BD%AC%E5%8F%91ipv6%E7%BD%91%E9%A1%B5%E8%87%B3ipv4/</guid>
      <description>Descript for artical</description>
      <content:encoded><![CDATA[<h2 id="intro-起因为-follow-添加小红书全文获取">Intro 起因：为 follow 添加小红书全文获取</h2>
<p>事情的起因是为了部署 Rsshub 服务为自己的 folo 提供小红书的全文解析，而 folo 是不支持本地/ipv6 的 rsshub ，因此需要将对应设置好小红书 cookie 的 rsshub 服务部署到 ipv4 的公网环境之下，权衡之下采取了该方式进行。</p>
<p>以下简单介绍一下自己的尝试过程：</p>
<ul>
<li>首先尝试利用 vercel 部署：由于部署 <a href="https://docs.rsshub.app/zh/deploy/" target="_blank" rel="noopener">rsshub</a>
 到 vercel 的方式目前还没修复，如果<a href="https://github.com/DIYgod/RSSHub/issues/14622" target="_blank" rel="noopener">使用 legacy 分支部署</a>
，也无法支持小红书的全文获取的需求，对应的环境变量可以直接在 github  rsshub 仓库的根目录直接添加 <code>.env</code> 文件即可。</li>
<li>其余的部署方式部分是需要收费的，或者说注册起来比较麻烦就没有再去尝试；</li>
</ul>
<p>本地尝试全文获取主要感谢以下作者的探索和分享，这里不再重复分享，通过添加 Cookie 的方式获取了小红书的 全文 Rss 源：</p>
<ul>
<li><a href="https://blog.gujiakai.top/2024/09/xiaohongshu-rss-tips/" target="_blank" rel="noopener">顾佳凯的网络日志 | 小红书RSS的解决方案</a>
</li>
</ul>
<p>但是由于小红书反扒严重，因此使用该方案还是要小心被封或者稳定性等问题，故而暂时没有将该 rsshub 源公开出来。</p>
<p>rsshub 的其余部署细节和配置可以参考：<a href="https://docs.rsshub.app/zh/" target="_blank" rel="noopener">RSSHub</a>
 官网的文档，这里不在赘述，</p>
<h2 id="转换-ipv6-服务到-ipv4-环境">转换 ipv6 服务到 ipv4 环境</h2>
<p>我们也知道获取公网的 ipv6 地址是比较容易的，通常普通家庭或者宽带都不会有公网的 ipv4 ，在此情况下 ipv6 的访问支持也并没有十分普及，在一些公共网络环境或者一些公司网络中，很多部署在 ipv6 环境下的网页实际上是没法被访问到的，而通过流量访问，还是有其局限性（流量收费限制）；</p>
<p>因此这里就尝试通过免费的 CloudFlare 的 CDN 服务来将 ipv6 服务代理到 ipv4 环境中，以下是一些相关的资料：</p>
<ul>
<li><a href="https://www.ztianzeng.com/posts/Cloudflare%E8%AE%A9IPV6%E4%B8%8D%E5%9C%A8%E9%B8%A1%E8%82%8B/" target="_blank" rel="noopener">Cloudflare让IPV6不在鸡肋 | 天增的博客</a>
</li>
<li><a href="https://post.smzdm.com/p/avxzg2gm/" target="_blank" rel="noopener">利用cloudflare让ipv4与ipv6互通_NAS存储_什么值得买</a>
</li>
<li><a href="https://www.bilibili.com/opus/969223623124451365" target="_blank" rel="noopener">使用Cloudflare代理为纯IPv6站点添加IPv4访问 - 哔哩哔哩</a>
</li>
</ul>
<h3 id="转换腾讯云解析到-cloudflare">转换腾讯云解析到 Cloudflare</h3>
<blockquote>
<p>使用 CF 的 CDN 的方式的先决条件是已经有了自己的域名，同时已经通过/可以通过公网 ipv6 发布自己的服务</p>
</blockquote>
<p>Cloudflare 官网： <a href="https://dash.cloudflare.com/" target="_blank" rel="noopener">https://dash.cloudflare.com/</a>
</p>
<p>主要参考<a href="https://blog.csdn.net/qq_38894585/article/details/131054885" target="_blank" rel="noopener">开启 Cloudflare CDN 代理，实现 IPv4 to IPv6 转换_ipv4转发ipv6-CSDN博客</a>
 一文，在已经基于 ipv6 部署了服务的情况下，参考该博主的文章将域名的 DNS 解析服务转换到 CF 即可，但是后续可能会遇到访问服务的时候反复重定向的问题，这里可以参考[TroubleShooting]( ### CloudFlare 网站【重定向次数过多】) 部分的解决方案；</p>
<p>P.S. 备注</p>
<ul>
<li>后续还是可以在腾讯云的控制台对子域名申请免费证书，对应的解析在 CF 中进行即可，</li>
<li>后续对应子域名的添加可以借助 DDNS-GO 直接更新到 CF 中即可</li>
<li>CF 对于服务的端口是有要求的，笔者本地是通过 Nginx 进行反向代理各项服务的，因此只需要处理好域名的对应关系即可。</li>
<li>通过这种方式，可以使用一个备用域名来将自己的一些服务部署到 ipv4 上。</li>
</ul>
<h2 id="troubleshooting-一些问题解决">Troubleshooting 一些问题解决</h2>
<h3 id="为-cloudflare-配置-ddns-go-动态更新-ipv6-地址">为 CloudFlare 配置 DDNS-Go 动态更新 ipv6 地址</h3>
<p>这里 DDNS-Go 的配置没有什么特别的，主要就是要获取 CloudFlare 的密钥，填入对应的配置中即可，具体的密钥获取位置如下：</p>
<p>首先进入 Profile 页面：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20250331001823.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20250331001823.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20250331001823.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>选择 API Tokens 中创建一个新的 Token</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20250331001907.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20250331001907.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20250331001907.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>选择 Edit zone DNS 模板后设置自己要操作的域名如下，最后点击确定即可获取需要的 Token</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20250331002118.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20250331002118.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20250331002118.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>DDNS-Go 的话只需要新增一个 Cloudflare 的配置，填入对应的 token 后，在 Ipv6 的部分添加你要跟踪的子域名即可，如果域名不存在 Cloudflare 中，其会自动完成对应记录的添加：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20250331002310.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20250331002310.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20250331002310.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><strong>Ref</strong>: <a href="https://zhuanlan.zhihu.com/p/581967733" target="_blank" rel="noopener">3、使用DDNS-GO配置DDNS，通过cloudflare api修改指定域名对应的动态ip - 知乎</a>
</p>
<h3 id="cloudflare-网站重定向次数过多">CloudFlare 网站【重定向次数过多】</h3>
<p>通常都是由于 SSL/TLS 的设置冲突导致的，这里只需要去 CloudFlare 管理面板的 SSL/TLS 菜单中将安全策略改为 Full（Strict）即可解决。</p>
<p>具体操作如下图：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20250331001459.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20250331001459.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20250331001459.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20250331001546.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20250331001546.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20250331001546.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>ref：<a href="https://blog.csdn.net/qq_37126941/article/details/122540553" target="_blank" rel="noopener">使用 CloudFlare 导致网站「重定向的次数过多」解决方案_wordpess 使用 cloudfare 重定向次数-CSDN博客</a>
</p>
<h2 id="fi">Fi</h2>
]]></content:encoded>
    </item>
    <item>
      <title>VPA03-量价分析的全局视角</title>
      <link>https://aikenh.cn/posts/vpa03-%E9%87%8F%E4%BB%B7%E5%88%86%E6%9E%90%E7%9A%84%E5%85%A8%E5%B1%80%E8%A7%86%E8%A7%92/</link>
      <pubDate>Sat, 08 Feb 2025 17:39:34 +0000</pubDate>
      <guid>https://aikenh.cn/posts/vpa03-%E9%87%8F%E4%BB%B7%E5%88%86%E6%9E%90%E7%9A%84%E5%85%A8%E5%B1%80%E8%A7%86%E8%A7%92/</guid>
      <description>Descript for artical</description>
      <content:encoded><![CDATA[<blockquote>
<p>本篇中所有专业人士、做市商、大型操盘手、专业投资者都简单的称之为局内人/庄家，他们就是试图赚取股票的批发和零售差价的商人。于股票市场而言是专业人士、局内人和做市商，对于期货市场则是大型操盘手，而外汇现货市场仍是做市商。</p>
</blockquote>



  
  

<blockquote class="alert-blockquote alert-todo">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Todo</span>
  </p>
  <p>需要对各个阶段的具体表现做一下梳理，各个阶段我们到底希望能在 k 线图中看到什么形态。</p>

</blockquote>
<h2 id="量价分析的全局流程">量价分析的全局流程</h2>
<pre class="mermaid">---
title: 量价分析的三个步骤
---
flowchart LR
A[细致分析单 K 线] --&gt; B[分析最新的几根 k 线] --&gt;C[分析全局趋势]
  </pre>
  <p>前文中已经介绍了量价分析中的前两步，从最新的几条 k 线中获取异常或者反转信号，但还需要从全局趋势中获取当前信号发生所处的点位，从而对信号发生的实际和幅度有所估计，这也是本章要讨论的：<strong>量价分析中的全局视角</strong>。</p>
<blockquote>
<p>要理解专业交易者的做法，投资者应该学会从一个试图以零售价格卖出手中股票存货的商人的角度进行思考，在他们清空货架上的存货的同时，出于盈利的目的，他们将以批发价格买入更多的商品，这是他们调整市场价格的首要目的。</p>
</blockquote>
<p>在进行量价分析中全局视野的学习之前，首先要理解几个基本概念，或者说是商人的几个行动阶段/模式：</p>
<pre class="mermaid">---
title: 局内人的行动模式
---
stateDiagram-V2
  direction LR
  state 吸筹阶段{
    需求测试 --&gt; 吸筹
  	吸筹 --&gt; 买入高峰
  }
  state 派筹阶段{
    供给测试 --&gt; 派筹
  	派筹 --&gt; 抛售高峰
  }
  买入高峰 --&gt; 供给测试
  抛售高峰 --&gt; 需求测试
  </pre>
  <blockquote>
<p>吸筹与派筹在所有时间跨度中无休止的循环往复，有大波动也有小波动,通过因果定律对每次吸筹和派筹的规模进行不同的分析。</p>
</blockquote>
<ul>
<li><a href="%e5%90%b8%e7%ad%b9.md">吸筹阶段</a>
：庄家调整市场试图以批发价买入股票储备的阶段（具体查看吸筹部分的文档）</li>
<li><a href="%e6%b4%be%e7%ad%b9.md">派筹阶段</a>
：庄家抬高股票价格，以零售价卖出手上的筹码（股票储备）的阶段（具体查看派筹部分的文档）</li>
<li><a href="%e4%be%9b%e7%bb%99%e5%92%8c%e9%9c%80%e6%b1%82%e6%b5%8b%e8%af%95.md">供给测试阶段</a>
：为了避免从吸筹阶段转向派筹阶段时，推高股价的过程中遭遇阻碍，卖家过多使得推高过程中价格下跌，需要从头开始吸筹，因此通过供给测试来判断市场上的卖家是否已经被消化，再推动市场进入派筹阶段。</li>
<li><a href="%e4%be%9b%e7%bb%99%e5%92%8c%e9%9c%80%e6%b1%82%e6%b5%8b%e8%af%95.md">需求测试阶段</a>
：和供给测试一体双生，是为了准备从派筹阶段转向吸筹阶段的过程中，降低市场价格的过程中不会受到买压的阻碍，测试市场是否已经准备好走向下跌。</li>
</ul>
<p>这样的吸/派筹阶段和需求/供给测试过程，就是我们在股市中需要寻找的重要信号，而且需要注意的是，<strong>往往在吸筹或者派筹阶段以后会有多次而不是单次的测试</strong>，一次比一次的成交量更低，当<strong>价格突破</strong>了这几次测试造成的<strong>震荡区间</strong>，就说明下一步行动（或者说我们期待的反转，将要到来了）</p>
<blockquote>
<p>在理解抛售高峰和买入高峰的时候，需要注意的是这两个定义并不是针对市场的，而是指的是局内人操作中的买入和抛售高峰。此外在了解这两个概念之前，了解一下附录提到的问题可能对概念的理解有所帮助。</p>
</blockquote>
<ul>
<li><a href="%e6%8a%9b%e5%94%ae%e5%92%8c%e4%b9%b0%e5%85%a5%e9%ab%98%e5%b3%b0.md">抛售和买入高峰</a>
：在<strong>吸筹和派筹最后阶段</strong>的操作，用于清空最后的存货，此时的 k 线会呈现<strong>长影线、低实体、高成交量的特点</strong>。</li>
</ul>
<p>总结一下这几个阶段可能会出现的一些特点：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: center">Stage</th>
          <th style="text-align: center">Feature</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: center">吸筹</td>
          <td style="text-align: center"></td>
      </tr>
      <tr>
          <td style="text-align: center">派筹</td>
          <td style="text-align: center"></td>
      </tr>
      <tr>
          <td style="text-align: center">供给测试</td>
          <td style="text-align: center"></td>
      </tr>
      <tr>
          <td style="text-align: center">需求测试</td>
          <td style="text-align: center"></td>
      </tr>
      <tr>
          <td style="text-align: center">买入高峰</td>
          <td style="text-align: center">低实体、长上影线、高成交量</td>
      </tr>
      <tr>
          <td style="text-align: center">抛售高峰</td>
          <td style="text-align: center">低实体、长下影线、高成交量</td>
      </tr>
  </tbody>
</table>
<ul>
<li><input disabled="" type="checkbox"> 整个局内人的完整工作流程就如下，但是我们需要更加清楚其如何吸引买家、卖家的入场，以及需要梳理一下各个阶段的特点。</li>
</ul>
<img src= https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250212162238.png height=450px>
<blockquote>
<p>这种周期可以存在于任意时间跨度和任意市场。上述情况可能出现于某一货币对的5分钟图中，可能持续数小时。同样，也可能存在于股票的日线图中，持续数周或数月。可能存在于期货合约的小时图中，这种情况下局内人将是大型操盘手，这一周期可能持续数天至数周。时间尺度并不重要，重要的是威科夫的“因果定律”</p>
</blockquote>
<h2 id="基本场景和概念辨析">基本场景和概念辨析</h2>
<p>这里对上述量化分析的全局视角中的一些情况做补充说明。</p>
<h3 id="吸筹和派筹中的目标价值区间是如何确定的">吸筹和派筹中的目标价值区间是如何确定的</h3>



  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>他们并不是提前计算好目标价值区间的值，而是局内人清楚每次市场震荡时，当前价格所处的位置，即是停滞或是要发生反转。</p>

</blockquote>
<p>在任意的价格图表中，都会存在价格震荡区域，在这些区域中可以认为是一些超买或者超卖的时刻，在这种区域，市场要么在寻找阻力位，要么在寻找支撑位，他们共同定义了一道价值屏障，在这里趋势<strong>要么延续，要么反转</strong>；</p>
<p>局内人正是清楚这些区间所在的位置（是一个原先趋势的短暂停滞，还是一个新的趋势形成了），因此将这些区间作为天然的吸筹和派筹的区间。</p>
<p>以一个派筹阶段为例，我们看抛售高峰中究竟发生了什么：</p>
<ol>
<li>市场本身上涨多时，随着利好信息的加速，市场进入目标区间，出现<strong>超买/卖情况</strong>中；</li>
<li>开始行动：<strong>正面消息支撑，牛市趋势上升，点位停滞派</strong>筹；</li>
<li>初始阶段为<strong>自然阶段</strong>：由局内人驱动的牛市动能自然而然的带动市场上升，成交量高（于平均值）但是不突出，该阶段局内人<strong>仅需满足投资者和投机者的需求卖出</strong>即可。</li>
<li>后期的<strong>抛售高峰</strong>：为局内人<strong>主要发力的阶段，市场非常弱势</strong>，买方被卖方淹没，这时局内人需要不顾一切的支撑市场（利好消息等），甚至推高价格，并开始大量抛售。（他们的卖盘本身会使得价格下跌，为了市场不向不利的方向运动，做市商的努力最终就会导向那个 k 线图。）</li>
</ol>
<p>还是一直反复说的，<strong>大买盘或者卖盘都会直接对价格造成对自己不利的影响，因此需要隐蔽或者拆分成小笔的去进行</strong>，也就是为什么行动会被分散在同一个时期的不同时间点。</p>
<h2 id="附录-1-常见问题">附录 1 常见问题</h2>
<h3 id="为什么上涨总是比下跌需要更多的时间">为什么上涨总是比下跌需要更多的时间</h3>
<p>从局内人的角度出发，，此外考虑到心理学的以下要素，可以知道太迅猛的涨跌和频繁的波动将会吓跑投资者，这并不是局内人乐意见到的。</p>
<ul>
<li><strong>贪婪与恐惧的不对称性</strong>：投资者在盈利时倾向于逐步获利了结（导致上涨缓慢），而在亏损时因恐慌可能集中抛售（加速下跌）。行为金融学中的<strong>损失厌恶理论</strong>表明，人们对损失的敏感度远高于同等收益，这放大了下跌时的抛售压力。</li>
<li><strong>预期形成机制</strong>：上涨趋势需要持续的利好信息积累信心，而负面消息可能迅速摧毁市场共识。</li>
</ul>
<p>因此局内人会通过缓慢的推高市场，然后逐渐加大脚步，使买家逐渐建立起信心，并产生市场具备向上的动量的错觉，由此来吸引买方；并且局内人也希望自己隐蔽自己的意图，一次性大量的成交会造成大量的价格波动，且会吸引注意，因此需要徐徐图之。</p>
<p>整个<strong>上涨流程就是通过 FOMO 情绪</strong>：上涨趋势开始加快步伐，价格逐级抬升，短暂停滞，小级别反转，吸引买方，同时引诱他人，然后继续上涨，直到接近派筹区域，其中因卖方了结利润所造成的小级别反转而小幅增加，帮助维持派筹行动最后一阶段的持仓水平。这正是市场在经历一系列更高的高点和低点、伴随短暂停滞和小幅回撤、继续上涨的原因。（因为有其余卖方的存在？）</p>
<p>而<strong>更好的下跌方式就是制造恐慌</strong>，利用厌恶损失的心里来造成大规模的连锁反应迅速下跌。</p>
<h3 id="填满仓库和清空仓库一般需要多久">填满仓库和清空仓库一般需要多久</h3>
<p>这个问题的答案就是<strong>这些周期存在于任意时间跨度下</strong>，从跳动点图，到1分钟图、 15分钟和60分钟图，然后到日线图、周线以及月线图。理解这一点的最好方法就是想想一个俄罗斯套娃：</p>
<ul>
<li>首先，这些周期存在于所有时间跨度，其次，通过观察多个时间跨度下的价格行为，你将可以发现这些是如何形成、呈现以及相互间确认的。一个在1分钟图中已经开始的周期，可能会在5分钟图中慢慢显现，也可能在15分钟图中刚刚发展。</li>
</ul>
<p>虽然这些阶段在所有的时间周期中都存在，但是从某种意义上讲，短期或长期的图表都能提供微观的、远视的视角以观察已经发生的事件。在分析中，<strong>我们需要结合这两者，才能做出投资方面的理性决策</strong>。</p>
<p>因此我们需要通过短或者极短的时间跨度下观察市场的微观结构，然后用更长的时间跨度来给予我们更宽广的视角来观察量价关系。再次强调，这些都是相对的，对于一个超短线交易者而言，这可能是5分钟、 15分钟或者60分钟图。而一个波段交易者可能会考虑60分钟、 240分钟和日线图。一个趋势交易者可能会使用4小时、日线以及周线图。</p>
<h3 id="高频交易的策略类型">高频交易的策略类型</h3>
<ul>
<li>做市：与传统的做市行为一样，这一策略通过为市场双方提供流动性以此赚取差价从而获利。</li>
<li>套利：当套利机会出现时交易（例如：指数、交易型开放式指数基金以及美国存托凭证与它们各自基础资产间的错配定价）。</li>
<li>结构性策略：这些策略通过寻找从市场或者特定交易者的结构性弱点进而占取先机，包括潜伏套利和塞单交易。</li>
<li>方向性策略：这些策略试图抢在价格变动前，或者直接引发价格变动，包括指令占先和趋势引发。</li>
</ul>
<h3 id="市场操纵是否意味着局内人可以任意操控价格变动">市场操纵是否意味着局内人可以任意操控价格变动</h3>
<p>局内人并不能任意操纵价格的变动，这里市场操纵的本质是通过引发投资者的恐惧与贪婪情绪来影响市场价格走势，而不是直接操控价格。局内人（如专业人士和做市商）无法垄断市场，他们只能协同作战并利用所有可用资源（如媒体新闻）来 manipulating 市场情绪，从而推动价格向其预期方向移动。成交量是确认局内人是否参与价格变动的关键指标，高成交量在买入或卖出高峰时会揭示他们的操作行为。</p>
]]></content:encoded>
    </item>
    <item>
      <title>VPA02-从价格行为交易开始</title>
      <link>https://aikenh.cn/posts/vpa02-%E4%BB%8E%E4%BB%B7%E6%A0%BC%E8%A1%8C%E4%B8%BA%E4%BA%A4%E6%98%93%E5%BC%80%E5%A7%8B/</link>
      <pubDate>Tue, 21 Jan 2025 14:30:36 +0000</pubDate>
      <guid>https://aikenh.cn/posts/vpa02-%E4%BB%8E%E4%BB%B7%E6%A0%BC%E8%A1%8C%E4%B8%BA%E4%BA%A4%E6%98%93%E5%BC%80%E5%A7%8B/</guid>
      <description>Descript for artical</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>从交易员从场内到线上的转变为引，引出线上交易缺少对市场情绪的感知，因此需要通过成交量来补齐这一信息；此外以价格行为交易方法<span class="sidenote-number"><small class="sidenote">PAT Price Action Trade</small></span>来介绍阅读 K 线的方法，并为后续的 VPA 做铺垫（PAT 方法实际上是 VPA 的一部分，只是没有做成交量的确认）</p>

</blockquote>
<p>P.S：</p>
<ul>
<li>美股绿涨红跌默认 A 股红涨吕跌默认，本笔记中暂时适用红涨，后续再做调整。</li>
<li>成交量本身没有颜色，颜色是为了区分当日的涨跌，和价值图表的颜色一致。</li>
</ul>



  
  

<blockquote class="alert-blockquote alert-todo">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Todo</span>
  </p>
  <p><ul>
<li><input disabled="" type="checkbox"> 分析影线和实体的所有不同构成能反应的不同猜测</li>
<li><input disabled="" type="checkbox"> 每次遇到不同的 k 线图区间，最好介入自己的分析，来完善整个理论</li>
</ul>

</blockquote>
<h2 id="场内交易到场外交易的失败">场内交易到场外交易的失败</h2>
<p>场内交易员可以通过场内人的表现，来感受到<strong>贪婪、恐惧；以及通过场内交易席位的买卖状况来判断市场的情绪</strong>，这也就是所谓的&quot;市场的气味&quot;，场外线上交易缺乏了这种气味（信息）,仅凭借<strong>价格行为</strong>进行交易也导致很多交易员的转型失败。</p>
<p>不可否认的是：价格行为确实存在一些信息和作用如下：</p>
<pre class="mermaid">flowchart LR
A[全球新闻动态]--浓缩--&gt;C[价格行为]
B[交易员和投资者的观点和决策]--浓缩--&gt;C

C--详尽分析--&gt;D[未来市场的运行方向]
  </pre>
  <p>但是在场内，可以通过观察得到以下的这些<strong>额外的信息，其隐藏在表现之下</strong>，能够帮助我们在价格行为至上，做出更加准确的决策，而不至于被市场欺骗，同时更加敏锐和有效：</p>
<pre class="mermaid">timeline
	title extra info in floor trading
	参与人数: 成交量
	电话竞拍的速度: 活跃度
				: 成交速度的相对大小
	交易的紧张和犹豫: 成交速度的变化
			 : 价格变动的停止
			 : 成交速度减缓
	
  </pre>
  <p>而这些场内的一些额外信息，在在线交易时，可以通过以下的替代指标来感受市场的供求关系和情绪的发展变化。</p>
<ul>
<li>成交量的相对大小</li>
<li>成交活跃度</li>
<li>成交速度的相对快慢</li>
<li>成交速度的变化（一阶导）</li>
</ul>
<p>有真实情绪的市场和价格的变动相互印证，就可以避免被拍卖商（或者说是定价商，券商，做市商）的虚假竞拍（抬价）所欺骗，从而使得在合适的价格购入对应的商品。</p>
<p>换句话说，<strong>再被操纵的市场中，成交量可以揭示价格变动背后的原因；而在未被操纵的市场中，成交量可以真实的反应市场的情绪和交易指令集。</strong></p>
<p>在 VPA 之前，我们先更深入的研究其中的 PA（T）<span class="sidenote-number"><small class="sidenote">price action trade</small></span></p>
<h2 id="pat-价格行为交易">PAT 价格行为交易</h2>
<blockquote>
<p>价格作为一个领先指标，它本身只能显示过去的事实，通过分析我们预测未来可能发生的情况，也许我们可以通过价格获得正确的预测，但是成交量可以让我们做的更加完整和可靠。</p>
</blockquote>
<p>价格最重要的四个组成部分为：<strong>开盘价</strong>、<strong>最高价</strong>、<strong>最低价</strong>、<strong>收盘价</strong>； PAT 就要求通过这些数值的曲线，去感受情绪，一个典型的例子就是<strong>开盘时价格的跳空</strong>，开盘时价格突然远超或远低于前日价格，这能使得我们感受市场的强烈情绪。</p>
<p>但不得不提的是，随着全球电子交易系统带来的期货、<strong>股指期货</strong>的 24 小时交易制度，使得开盘价和收盘价的重要性没有以往那么重要（<strong>特指具备股指期货的股票指数等</strong>，对单只股票而言，其仍然受大盘和市场情绪的影响，还是很重要的），或者说重要性可以被夜盘的期货市场替代，其在<strong>夜盘中的交易能使我们提前感受市场的情绪，因此开盘价的变化就不再使人意外</strong>。</p>
<pre class="mermaid">flowchart LR

A[现货-股指] --衍生--&gt; B[股指期货]--夜盘交易--&gt;C[情绪变化]
C--开盘点位变化--&gt;A
  </pre>
  <blockquote>
<p>这种 24 小时交易会使得跳空变少或者情绪变化的表达更加含蓄/缺失，因此成交量的信息也愈发重要。</p>
</blockquote>



  
  

<blockquote class="alert-blockquote alert-idea">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Idea</span>
  </p>
  <p>是否可以利用夜盘的信息来从盘后交易中获利？</p>

</blockquote>
<p>这并不意味着 PAT 就没有意义了，只是说相比于传统市场缺失了一部分信息，再次强调了成交量的重要性罢了，而要想读懂价格中仍然蕴含的信息，我们需要学会阅读 K 线图，k 线图中蕴含了价格的四大重要组成。</p>
<h3 id="k-线图的形态和基本阅读方法">K 线图的形态和基本阅读方法</h3>
<blockquote>
<p>在相应的时间框架内，每一个元素在分析价格行为时都起着相应的作用；另一方面，当我们适用成交量加以验证的时候，影线和实体最能揭示市场情绪。</p>
</blockquote>
<h3 id="k-线图的基本元素">k 线图的基本元素</h3>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250122131443.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250122131443.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250122131443.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>通过上图的形式，将 K 线图解读成一个正弦波，随着市场的上下震荡，买方和卖方争夺控制权的主导地位，在上涨形势中买方最终占据主导权，整个过程可能十分曲折，但是我们只需关注最终形成的趋势即可。接下来我们就需要从中阅读市场情绪：</p>
<p>一、<strong>实体的长度/高低预示市场情绪的热烈程度</strong>，高实体意味着情绪强烈，低实体意味着情绪低迷
二、<strong>影线代表着变化，或者说是意见分歧</strong>，因此影线的长度和含义，在量价分析中无比重要。</p>
<h3 id="k-线图中的实体和影线">k 线图中的实体和影线</h3>
<blockquote>
<p>正如上一小节中所说，实体长度象征市场情绪的激烈程度，而影线代表着具体变化过程；</p>
</blockquote>
<p>实体而言：假如市场情绪始终都十分强烈且统一，那么我们将得到一个高实体且没有影线的 K 线图，这意味着市场始终向一个方向前进且没有质疑，该市场<strong>情绪强烈且将持续</strong>。</p>
<p>而<strong>影线</strong>由于其代表了变化和分歧，<strong>其长度和含义在量价分析中是无比重要</strong>的，下面有两个例子：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250122135040.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250122135040.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250122135040.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>这是一个<strong>不存在实体的下影线</strong>，可以认为开盘后卖方占据了主导地位，力量超过了买方，导致价格下跌，随着价格下跌，对买方的吸引力上升，买方的力量逐渐压过了卖方，买家涌入市场，这意味着两点：</p>
<ol>
<li>无论周期多长，市场情绪出现了反转；</li>
<li>收盘时市场处于看涨情绪中，这是由于买压暂时处于主导地位，（也有可能已经平衡？）</li>
</ol>
<p>但是其并不能作为趋势反转的信号，因为仅凭借价格还没有足够的信息量，去判断当前买压的剩余力量是多少，还是已经达到平衡。如果需要得到这个信息，就需要分析在反转过程中发生了什么，这里就可以借助量价分析 VPA 中的 价量分布分析 VAP <span class="sidenote-number"><small class="sidenote">即Volume at Price</small></span>.</p>
<blockquote>
<p>通过在价格变动中的成交量变化，我们就可以基于成交量来衡量买压和卖压的大小，两股力量是否达到平衡，也能利用成交量的变化速度，变化加速度，即一阶导和二阶导，去评估这个力量的平衡价位等。(需要考虑市场是动态的，而不是不变的系统)</p>
</blockquote>
<p>下面这个上影线的例子，和下影线的例子的分析是一样的：</p>
<ol>
<li>市场情绪出现了反转</li>
<li>收盘时市场处于看跌情绪中</li>
</ol>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250122133435.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250122133435.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250122133435.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>这种 k 线图可以是跳动点图上的，可以是五分钟、日线、周线，都是一样的，当我们在日线图和周线图上评估趋势，并在 1、5 分钟图上结合成交量去分析价格行为时，意义更大。</p>
<p>这两种 k 线图是非常重要的价格形态，后面还会反复回顾；目前在分析上还欠缺的是：</p>
<ul>
<li>价格行为的强度，即上述说的是否达到平衡，可能需要借助 VAP 分析；</li>
<li>这种价格行为是否有效：即是否是真实的符合市场的价格运动。</li>
<li>后续如何发展。</li>
</ul>
<p>这些就需要结合成交量去分析了。</p>
<h2 id="vpa-的基本原则">VPA 的基本原则</h2>



  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>本章节并不是具体的分析技术和细节，而是涉及分析过程中的行动纲领，以及对整个方法的基本认知。</p>

</blockquote>
<h3 id="vpa-是艺术并非科学">VPA 是艺术并非科学</h3>
<p>在量价分析中，我们要做的通常是如下的两点：</p>
<ol>
<li>对比分析价格行为和对应的成交量，寻找相互印证或者异常；</li>
<li>对比历史成交量判断当前成交量的大小；</li>
</ol>
<blockquote>
<p>因此主要的成本是如何获取实际的成交量。</p>
</blockquote>
<p>而在这个过程中，作者认为相互印证或者成交量的相对大小的判断，没有一个准确的标准，大部分的判断都是主观的，因此不具备主观能力的软件程序无法胜任量价分析的任务，<strong>即 VPA 是艺术而非科学</strong>。</p>
<hr>
<p>但是考虑到当前 AI 技术的发展，无论是适用 DPO、强化学习、偏好模仿、还是针对单独的股票进行独立建模在使用 moe 进行统一分析，我认为都能模拟人类的主观偏好以及后续自我进化的特点，因此我认为其并非无法适用软件去替代进行决策。</p>
<p>就算对应完全替代的路线难度很大，适用软件去获取置信度较高，或者需要警惕的信号做保底策略来简化人类监管也是大有可为的。</p>
<h3 id="耐心等待转变">耐心等待转变</h3>
<blockquote>
<p>金融市场犹如一艘巨大的游轮，他不会戛然而止又迅速启动，市场通常<strong>拥有动量</strong>；反转终究会到来，但不是在某根 k 线图发出信号后立即到来，在它准备好反转之前，将首先完成清理的工作。</p>
</blockquote>
<p><strong>耐心原则</strong>：当 K 线图形态预示潜在的反转或异常时，市场的趋势仍然会继续持续一段时间。</p>
<p>这可能也是量价分析会 Work 的原因：信号提前于趋势的发生，通过类似加速度正负转变的方式，在利用 delay 时间清楚原有势力或者说动量后，才实现趋势的反转，整个过程好比趋势曲线是 S，发展方向取决于 V，转变信号则是 a 的正负转换，示例如下：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250124132211.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250124132211.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250124132211.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>



  
  

<blockquote class="alert-blockquote alert-todo">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Todo</span>
  </p>
  <p>复习一下动量理论，可以参考动量的定律来对市场进行一个基本的建模，单纯考虑 S-V-A-t 的运动理论就类似 PAT，其中的成因 Volume 就好比 F=ma ，而作为 F 的 Volume 还能以动量的形式来对市场的运动产生影响，两者之间是能相互印证的。</p>

</blockquote>
<p>回到具体的市场数值上而言，即从价格行为上看，买压或卖压在 Volume 和 Price 上的压倒性优势并非是瞬间形成的，而是一种逐渐转变的过程，通常可以看到下面这种流程：</p>
<ol>
<li>部分卖家坚信市场还会下行，继续坚持，市场下行了一小段后开始上行，越来越多的卖家离场</li>
<li>市场再一次下行到更低点位后开始反弹，通过这种方式将固执的卖家清洗出局</li>
<li>最后，清理完最后的卖家（&ldquo;扫尾&rdquo;）之后，市场做好了上行至更高点位的准备。</li>
</ol>
<p>这种拉锯过程（犹豫情绪）正是一段<strong>延伸行情</strong>中的<strong>价格震荡区间</strong>的成因，在这种即将反转的情况下，通常会遇到<strong>强力的支撑位</strong>和<strong>阻力位</strong>；</p>
<blockquote>
<p>是否包含如下的结构才是一个完整的趋势形成的信号?</p>
</blockquote>
<pre class="mermaid">flowchart LR
A[PAT 得到变动信号] --&gt; B[Volume 验证] --&gt; C[Volume 获取有效的
											支撑或着阻力]
C --&gt;  D[趋势将会到来]
  </pre>
  <h3 id="成交量的核心在于相对性">成交量的核心在于相对性</h3>
<p>由于我们<strong>关注的是成交量的相对变化</strong>，因此无需纠结于成交量获取的数据有多么的准确，但是<strong>数据的一致性是十分重要</strong>的，只要在我们分析的阶段数据的来源和统计方法是一致的即可。</p>
<p>这里通过作者的长时间实践和纠结发现是正确且可行的，一个<strong>普通 MT4 平台的免费跳动点成交量数据</strong>也能满足我们的需求，且其还是免费的，作者已经使用了多年。</p>
<h3 id="熟能生巧">熟能生巧</h3>
<blockquote>
<p>历久弥新的熟能生巧四字真言；保持耐心，投入时间和精力，数周或者数月后会发现自己有预测市场反转的能力。</p>
</blockquote>
<p>上述提及，该方式适用于各种时间跨度的交易，因此在做实验的时候，可以：</p>
<ol>
<li>投资：从较长周期的日线图和周线图进行分析，寻找买入和持有的机会</li>
<li>投机：适用跳动点图或者短时间周期图进行日内交易；</li>
</ol>
<h3 id="技术分析">技术分析</h3>
<p>量价分析只是技术分析的一部分，通常结合其他的工具和方式对我们的预测进行确认，其中最重要的就是上述提到的<strong>支撑位和阻力位</strong>，该指标能描述市场在反转之前进行扫尾工作的阶段，又或者只是一段长期趋势的停顿点，都可以在后续的成交量分析中得到验证，但价格突破整理区间，伴随着适当的成交量，常常是一个强烈的信号。</p>
<p><strong>趋势分析</strong>、<strong>价格形态分析</strong>同样重要，都是技术分析的这门艺术的组成部分。</p>
<h2 id="vpa-的主要行为确认或异常">VPA 的主要行为：确认或异常</h2>
<pre class="mermaid">flowchart LR
A[开始] --&gt;B[价格被成交量确认]
A --&gt; C[价格中存在异常现象]
B--&gt; D[价格的连续性被确认]
C--&gt;E[存在潜在变化的信号]
  </pre>
  <p>量价分析实际上寻找的就是上述的两种情况，核心在于如何判断确认和异常，下面通过单一 K 线和多 K 线来介绍如何区分两种情况：</p>
<h3 id="单根-k-线图从微观出发">单根 k 线图：从微观出发</h3>
<h4 id="价格确认信号">价格确认信号</h4>
<p>首先介绍价格被确认的例子：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250124151349.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250124151349.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250124151349.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><strong>长阳线的例子</strong>，根据上述 PAT 的理解，我们可以看出<strong>价格强劲上涨</strong>，<strong>收盘价略低于最高价</strong>，同时存在较高的成交量来匹配这一较大的价格变化（威科夫第三定律，投入产出匹配），由此价格被成交量确认，因此可以假设两种情况：</p>
<ol>
<li>价格的变动是真实的，未收到操控；</li>
<li>市场处于牛市阶段，直到我们发现异常信号之前，都可以持有手中的长头寸；</li>
</ol>
<p><strong>短阳线的例子</strong>，这是一个伴随较低成交量的短阳线，具备幅度较小的价格变动（略微上涨），上影线和下影线也比较低，成交量也大幅低于平均水平，同样符合投入产出定义，较低的成交量促成较小的变动。（较低的投入只能促成较小的市场变动）。</p>
<h4 id="价格异常信号">价格异常信号</h4>
<p>接下来看下异常的例子：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250124170321.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250124170321.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250124170321.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><strong>长阳线异常的例子</strong>，其不符合威科夫的第三定律，有较大的价格变化（产出），但是仅有很少的市场参与（即成交量，即投入），这种异常出现时，我们需要考虑是否是市场或者做市商设下的多头陷阱。这种形态常常发生于：</p>
<ol>
<li>股票开盘，做市商基于夜盘中的信息判断市场的情绪处于牛市或熊市，然后通过抬高/降低价格来测试买家的兴趣，如果没有买家有兴趣，价格将会下跌，仅在买方会在高价进入市场时，他们才会继续抬高价格。后面再继续测试；通过这种方式来确定盘后九分钟的价格水平</li>
</ol>
<p>因此<strong>在开盘后的几分钟内盯紧图表，有助于我们明确当天的一个交易基调</strong>，同时我们也应密切关注相关的突发行为，因为做市商&quot;不会放过每一个制造危机的机会&quot;，他们会通过新闻的机会来测试市场，根据新闻抬升或拉低价格，都有可能使得类似的图表出现。</p>
<p>这是一种标志且明确的陷阱信号，这种价格的上涨会迅速的发生反转，市场相反方向运动。</p>
<p>🔥 <strong>短阳线异常的例子</strong>，其同样不符合威科夫的第三定律，这里小幅度的价格变化却由着大量的成交量造成，这种典型的 K 线图形态往往发生于<strong>牛市的顶部</strong>，<strong>或者熊市的底部</strong>。是一种<strong>市场趋于弱势的信号</strong>。举个例子来分析：</p>
<blockquote>
<p>假设：牛市情况
情形分析：持续了一段时间的上涨，主力多头开始了结利润，开始清仓卖出，而此时持有 FOMO 情绪的个人投资者拥入市场买入，此时由于主力在退出，个人投资者没有足够的能量来推动价格继续上涨，因此有大量的成交量却仅有较小的价格变动。此时买方仅稍胜卖方，但是如果趋势再往下后，可能也会出现反转，因为如果卖方十分坚定（强势）则会表现出阴线。
卖出对象分析：个人投资者通常存在追涨杀跌以及 FOMO 的特性，因此卖出的主要是了结利润的长期投资者，局内人，做市商，内幕交易者等；
剩余买家没法推动价格上涨，价格的上涨会引来更多的卖出，下跌则会有更多的买家，在该价位拉扯。</p>
</blockquote>
<p>因此这是一个市场走弱，而挣扎于保持现有水平的一个典型信号，如果原先持有头寸，就应该收拾收拾卖出，或者准备在趋势反转的时候建立头寸。</p>
<h4 id="了解信号的趋势背景">了解信号的趋势背景</h4>



  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>在 k 线图的解读中，对所处趋势的认知影响解读的方向，趋势对于信号的解读是必不可少的环节即：<strong>K线图在趋势中所处的位置不同具有的意义也不同</strong></p>

</blockquote>
<p>趋势对 k 线图分析的影响主要有以下的几类：</p>
<ul>
<li>时间跨度：信号是在 5 分钟图中，小时图，日图等发生的，对应的趋势周期和长度是不一样的，并非只有长期趋势才叫做趋势；</li>
<li>趋势中的位置定位：需要明确价格异常的信息具体引导向建立头寸还是卖出，需要借助趋势信息来明确我们在价格变动中所处的位置，</li>
</ul>
<p>而要分析趋势，明确信号带来的引导，寻找潜在的反转点，需要使用<strong>支撑位和阻力位、 K线图形态、单根K线图，以及趋势线</strong>进行分析。上述工具可以为我们提供我们的“方位”帮助我们确认价格变动中我们所处的位置。</p>
<h3 id="多根-k-线图宏观分析由点到线">多根 k 线图：宏观分析，由点到线</h3>
<h4 id="趋势确认信号">趋势确认信号</h4>
<p>以下图为例，这是一个连续上涨的 k 线：价格逐日上涨，且实体也逐日扩大，同样的成交量也满足一样的规律，逐日扩大。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250208150630.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250208150630.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250208150630.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>可以看出曲线上整体是符合威科夫第三定律的，较低的价格变化实体对应较小的成交量，同时较高的价格变换实体也具备更高的成交量的确认。从单线和多线上都印证了这是一个市场参与（受到了市场情绪和专业人士的共同支持）的正常价格变动，形成了一个成交量在增加的趋势的价格上涨趋势；</p>
<p>这里说明的是投入产出<strong>不仅适用于单线，也适用于多线</strong>的情况，这可以是我们进行<strong>双重确认</strong>；同时这里成交量和价格的变动也能用第二定律来解释即：此处结果的变动程度（趋势中的价格变动）和原因的规模（成交量在特定时间单位中的变动）是相关的，即上涨的价格与放大的成交量正相关。</p>
<p>假设上述的价格上升过程<strong>没有影线</strong>，我们可以认为，<strong>成交量均为买入的成交量</strong>（如果有卖出市场应该有所体现），市场坚定的上行，<strong>是一个低风险的交易机会</strong>。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250208153947.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250208153947.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250208153947.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>无需赘言，下跌的例子也可同样使用威科夫第三定律来确认价格变动是否是有效的，与上涨和下跌无关，同样，我们从两个层次去确认价格变动的合理性。</p>



  
  

<blockquote class="alert-blockquote alert-warning">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path>
    </svg>
    <span>Warning</span>
  </p>
  <p>后续需要确认一下这个逻辑是否是正确的</p>

</blockquote>
<pre class="mermaid">graph LR
    A[开始] --&gt; B{单 K 线分析}
    B --&gt; C[对比平均情况]
    C --&gt; D[实体和 V 的所处相对位置是否匹配]
    D --&gt;|是| E[进入多 K 线分析阶段]
    E --&gt; F[观察整个趋势中的价格变化]
    F --&gt; G[检查价格和成交量的变化是否一致]
    G --&gt;|是| H[确认价格走势]
    H --&gt; I[结束]
    D --&gt;|否| J[分析单 K 线异常]
  </pre>
  <h4 id="量价异常信号">量价异常信号</h4>
<p>以下图为例，价格在上涨，同时实体逐渐略微扩大，第一根 K 线的价格和成交量相互印证，但是其余 k 线却均有一些问题。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250208160414.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250208160414.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250208160414.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ol>
<li>k 线图 2 中实体较低却伴随着巨大的成交量，这是市场弱势的信号，这意味着主要操盘手（做市商）正在卖出，因为大量的投入没有产生对应的上涨效果。</li>
<li>k 线图 3 是一个连续异常，在趋势上他实体相对于 2 更高，但是成交量却更低，这也清楚的印证了 k 线图 2 中的异常</li>
<li>k 线图 4 再一次异常，实体更高了，但是成交量却更低，该趋势中明确存在异常行为。</li>
</ol>
<p>通过上述图的表现，可以有下面的结论：</p>
<p>首先 k 线图 2 中成交量的投入和价格产出的不匹配，体现了一个市场处于弱势的信号，市场处于&quot;超买&quot;的情况，做市商和专业人士感受到了市场的弱势，卖家享受做空机会，在这个点位大量卖出，等待价格下跌，同时继续<strong>抬高价格来创造盈利而非推动上涨</strong>，但是买方市场显然已经没有足够的能量推动价格继续上涨，下跌的成交量可以印证这一点，这是市场处于弱势的一个信号。</p>
<blockquote>
<p><strong>这也可能只是一个短暂停驻</strong>，并非趋势的大型变动，进一步的我们需要<strong>在更大的背景下分析图表</strong>，决定我们看到的是一个小幅度的回落还是趋势改变的征兆。这一点上就需要<strong>借助因果定律</strong>，<strong>从时间跨度和量的起因来分析</strong>这是一个小幅度的回落还是一个大的趋势的转向。</p>
</blockquote>
<p>这另一个<strong>多根柱状图异常下跌</strong>的趋势：价格持续下跌，实体逐渐扩大，成交量的变化却并不与之匹配，这里的分析和上述超买的情况类似，在第二个 k 线处开始发生异常。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250208164209.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250208164209.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20250208164209.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>同上述分析，可以有以下的结论：</p>
<p>k 线图 2 中低实体却对应的大量的成交，意味着市场拒绝向更低点位运动，<strong>卖压正在枯竭</strong>，做市商感受到了这个市场情绪，即越来越多的买家涌入开始买入，因此<strong>做市商</strong>在这一水平也开始执行买入，因此市场难以继续向更低点位运动，k3 和 k4 则是做市商继续调低价格，<strong>试图欺骗卖方市场仍处于熊市，使其继续卖出，从而自己能在更低价位买入，建立头寸</strong>。</p>
<p>由于做市商和专业人士转向了买方市场，从空头转向了买入，因此卖压开始枯竭，卖方不够支持成交量的上涨，来使得市场运行到更低的点位，因此也构成了一个信号。</p>
<p><strong>同样，有了这样的异常信号以后，我们还需分析进一步的信号，从因果定律出发，判断市场发生趋势反转的程度：是短暂回调还是大幅反转。</strong></p>
<blockquote>
<p>即使这是一个小插曲，也为我们提供了一个低风险的短期交易的机会。</p>
</blockquote>
<p>至此，我们从<strong>微观（单 K 线）出发</strong>建立成交量的相对状态的感知，然后从<strong>宏观分析（多 k 线）</strong>，得到小级别的趋势，或者潜在的小级别反转的确认，而还<strong>缺失的就是全局视角</strong>，了解价格在这个长期趋势中的位置，这也是后面要介绍的内容</p>
<h3 id="全局视角-intro">全局视角 Intro</h3>
<blockquote>
<p>我们从一根 k 线开始变焦到局部 k 线趋势，最终我们还需要看到更长时间上的大趋势，能够进一步的帮助我们理解市场运动，完善我们的局部分析，从而做出最终的决策，在这一部分，威科夫的第二定律：因果定律，就会大肆发挥作用。</p>
</blockquote>
<h4 id="理解全局视角">理解全局视角</h4>
<p>正如<strong>耐心等待转变</strong>原则所言，市场并非是获取转向信号后就立即转向，从全局视角出发，我们可以知道这正是由于：</p>
<p>“市场就像一艘油轮——在局内人、专业人士以及做市商准备好前，市场需要花一定的时间消化买盘或卖盘以完成转向。在他们确认实施下一步计划之前，不希望市场成为他的阻碍。”</p>
<p>上述两个例子就像是&quot;扫尾&quot;行动，这种扫尾行动可能在日线图上会间歇性的持续在数天、数周、数月中出现，市场持续震荡整理，出现多次连续的反转信号，<strong>来使得扫尾更加彻底，清楚市场的阻碍</strong>，但是我们不知道合适反转会发生，而威科夫的第二定律告诉我们，当整理的时间越长，幅度越大，反转就越可能发生，准备的周期越长，最后转变的趋势也会更加持久。</p>
<p>以上述的例子而言，当我们发现这 4 个例子反复在同个价格水平出现，而非单次出现，那么就可能不是一个小插曲，而是一个较大的趋势了，在这种时候我们应该<strong>耐心等候支撑位和阻力位的信号（后续）</strong>。</p>
<h4 id="实际策略操作举例">实际策略操作举例</h4>
<p>（日内交易为例）：结合 5 分钟、15 分钟、30 分钟图表进行市场分析：</p>
<ul>
<li>15 分钟图进行日内交易；</li>
<li>5 分钟图来获取靠近市场的视角；</li>
<li>30 分钟图来获取长期视角；</li>
</ul>
<p>一个趋势如果在 5 分钟图中发生，随机传导到 15 分钟、30 分钟图中，那么他就会发展成为一个较为长期的趋势，（判断信号用多长的时间来蓄势？从而判断反转发生的趋势的持续水平？）</p>
<h2 id="fi">FI</h2>
]]></content:encoded>
    </item>
    <item>
      <title>VPA01-基本市场行为描述</title>
      <link>https://aikenh.cn/posts/vpa01-%E5%B8%82%E5%9C%BA%E7%9A%84%E5%9F%BA%E6%9C%AC%E8%A1%8C%E4%B8%BA%E6%8F%8F%E8%BF%B0/</link>
      <pubDate>Mon, 20 Jan 2025 00:41:06 +0000</pubDate>
      <guid>https://aikenh.cn/posts/vpa01-%E5%B8%82%E5%9C%BA%E7%9A%84%E5%9F%BA%E6%9C%AC%E8%A1%8C%E4%B8%BA%E6%8F%8F%E8%BF%B0/</guid>
      <description>Descript for artical</description>
      <content:encoded><![CDATA[<blockquote>
<p>[!summary+]
量价分析<span class="sidenote-number"><small class="sidenote">Volume Price Analysis</small></span>，基于所有的金融市场都被幕后操作的假设，利用成交量是不可被隐藏和作假的特性，使用成交量来确认和预测价格运动。</p>
</blockquote>
<h2 id="intro-市场的基本行为">Intro 市场的基本行为</h2>
<p>从威科夫<span class="sidenote-number"><small class="sidenote">量价交易之父</small></span>提出的集散概念和价量至上原则开始：&quot;<strong>价格和成交量是决定股价波动的最重要因素</strong>&quot;。此外查尔斯·道<span class="sidenote-number"><small class="sidenote">技术分析之祖</small></span>的道氏理论中的一条基本原则也说&quot;<strong>成交量可以确定价格变化的趋势</strong>&quot;</p>
<blockquote>
<p>因此进行相应分析时需要包含成交量和价格的图表。</p>
</blockquote>
<p>From 《盘口解读》:</p>
<blockquote>
<p>在根据市场自身的表现来判断市场的时候，短期波动或长期波动都由<strong>价格</strong>、<strong>成交量</strong>、<a href="%e6%b4%bb%e8%b7%83%e5%ba%a6.md">活跃度</a>
、<a href="%e6%94%af%e6%92%91%e4%bd%8d%e5%92%8c%e9%98%bb%e5%8a%9b%e4%bd%8d.md">支撑位和阻力位</a>
 所反映。从海里一滴水的成分可以推断海的成分，反之亦然；</p>
</blockquote>
<h3 id="there-is-nothing-new-in-trading-适用性">There is nothing new in trading. 适用性</h3>
<p><strong>适用性：</strong>“日光底下无新事”，目前可以认为基于成交量进行的量价交易，到今天仍然是适用的，且适用于各种市场（不同投资类型），各种交易或投资策略中。</p>
<h3 id="daws-rule-1-成交量确定趋势的有效性">Daw&rsquo;s Rule 1 成交量确定趋势的有效性</h3>
<p>Daw‘s ’Rule1：成交量可以<strong>确定</strong>价格变化的趋势；
Detail 具体而言：</p>
<ul>
<li>当一个股票的波动伴随着较低的成交量，那么其变动的原因是多样且不能被确定的，其将不能被认定为存在一个有效的趋势；</li>
<li>而当一个股票的价格变动<strong>伴随着很高的或者逐渐增大的成交量</strong>，那么该变动是一个有效的变动，或者说，可以假设其具备构成一个趋势的基本条件（必要非充分）</li>
<li>在第二点的前提下，如果价格继续向着同一个方向变动，且拥有相应的成交量支撑，那么将是一段趋势开启的信号；</li>
</ul>
<pre class="mermaid">flowchart LR
A[成交量] --确认--&gt;B[价格行为/价格变动]--形成--&gt;C[趋势] 
  </pre>
  <p>Expand 理论延续：当满足条件的趋势形成，Daw 认为接下来的趋势会具备一下的三个阶段（Daw 的趋势理论）：</p>
<pre class="mermaid">timeline
title 成交量趋势的三个阶段
吸筹阶段: 更强趋势的起点
公众参与阶段: 趋势最终的阶段
		 : 最长的一个阶段
派筹阶段: 投资者蜂拥买入的 FOMO 阶段
	   : Daw&#39;s 止盈的时机
  </pre>
  <p>理解一个趋势的不同阶段，对后续做出决策还是有所帮助的。</p>



  
  

<blockquote class="alert-blockquote alert-note">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Note</span>
  </p>
  <p>成交量逐渐上升，是否就会形成一个供求关系的强烈变动，具体是如何 work 的呢？</p>
<ul>
<li>和流通量有什么关系？
买&gt;卖 =&gt; 上涨？因此最好在第三阶段卖出？</li>
</ul>

</blockquote>
<blockquote>
<p>股票指数的概念也是 Daw 提出的，通过行业指数等，可以追踪一个行业的整体状况从而了解宏观经济的运行情况；（大盘？）</p>
</blockquote>
<h3 id="wyckoffs-供需关系决定趋势">Wyckoff&rsquo;s 供需关系决定趋势</h3>
<p>Wyckoff&rsquo;s Opinion：价格完全是由经济学中最基本的供求关系决定的，通过观察价格和成交年的关系，完全可以预测未来市场的方向。</p>
<blockquote>
<p>他在对行业大师的采访中发现了共同点：行情纸带都是他们投资决策的依据，而行情纸带可通过其包含的信息：价格、成交量、时间、核心趋势来为我们揭示最基本的供求规律。</p>
</blockquote>
<p>Three Basic Laws 威科夫的三大基本定律：</p>
<p><strong>一、供求定律：</strong></p>
<p>当需求 &gt; 供给时，为了满足这样的需求，价格会上涨；相反地，当供给 &gt; 需求时，价格会下跌，结果就是超额的供给会被吸收；</p>
<p><strong>二、因果定律：</strong></p>
<p>有果必先有因，且因果之前呈现正比例相关，即：小规模的<strong>成交量变化</strong>将引起小范围的价格波动，重大的起因会导致重大的结果。</p>
<p>该因果定律并不只是指代变化规模上的，同样也能指代时间跨度上的，短时间图表上的成交量变化和长时间图表上的成交量变化，将会引导的是不同跨度和规模的趋势。</p>
<p><strong>三、投入产出定律：</strong></p>
<p>价格变动和成交量的变动呈现作用力和反作用力的关系，两者的变动应该有一种和谐统一的关系，即通过投入（成交量）即可预计相应的产出（相应的价格行为）。</p>
<p>分析每一条价格柱状图，看时候持续成立，如果是持续成立的，那么就可以继续适用该方法，进行预测，否则需要找到其背后的原因，分析异常，否则就不能在该股票上适用该方法。</p>
<hr>
<p>简单的总结如下：在验证符合定律的情况下，关注异常疲软的需求或者异常强劲的需求，在供需适配的地方会发生相应水平的价格变动。</p>
<pre class="mermaid">flowchart LR
A[投入产出定律]--验证有效--&gt;B[供求定律]--确定趋势--&gt;C[因果定律]--&gt;D[从需求中估计幅度]
  </pre>
  <h3 id="richard-ney-内幕交易永流传">Richard Ney 内幕交易永流传</h3>
<p>&ldquo;我们参与的投资市场或多或少的被操纵，包括做市商遮遮掩掩的行为，公开的一些政策干预等等&rdquo;，但是成交量是无法被隐藏的，成交量反应交易行为，反应价格变化背后的真实情况，检验价格变动的真实性。</p>
<blockquote>
<p>操纵：通过一些内幕消息和影响力（假消息等），来使得在各种交易中获利（根据自己的买入或卖出意愿来操纵价格），而不管股票的真实价值如何。</p>
</blockquote>
<ul>
<li><input disabled="" type="checkbox"> 这里有个专业人士的卖空之道的八大法则，目前没明白意义在哪，可能能帮助我们理解操纵行为吧，后续补充</li>
</ul>
<p>做市商的永恒存在可能也是对该点的一个佐证？<a href="%e9%87%91%e8%9e%8d%e5%9f%ba%e6%9c%ac%e6%9c%af%e8%af%ad.md">金融基本术语</a>
中参考做市商。</p>
<h2 id="volume-matters-利用成交量跟随内幕">Volume Matters 利用成交量跟随内幕</h2>
<blockquote>
<p>关键之处就在于获取比其他人更多的信息，然后正确地分析并使用他们 ——沃伦巴菲特</p>
</blockquote>
<h3 id="get-info-通过成交量来洞察内幕者的操作">Get Info 通过成交量来洞察内幕者的操作</h3>
<p>作为股票投资者，我们无法如同做市商一样获取市场的供给和需求水平，但是我们可以通过成交量间接了解这一情况，去间接的获取做市商的资讯。</p>
<p>这里<strong>成交量分析具备局限性</strong>：做市商会在交易发生数小时后才报告大众交易的数据，不过<strong>仍然是我们窥探市场的最好工具</strong>。</p>
<blockquote>
<p>由于做市商对应的操作会影响该信息的时效性，因此可能会影响量化交易策略的执行，不过也可以考虑其中的价值和成交量的失配是否会带来一些新的信息。</p>
</blockquote>
<p>无论做市商是否执行了某些操纵行为，成交量分析都是可以 Work 的，以下面这个分析为例：</p>
<pre class="mermaid">---
title: 牛市前提下
---
flowchart LR

A[期货价格上涨] --交易规模大&amp;--&gt; B[成交量扩张] --&gt; C[Valid]
A --&gt; E[成交量没有对应趋势]
D[期货价格下跌] --&gt; B
D --&gt; E
E --&gt; G[警惕市场/做市商的欺骗]
  </pre>
  <p>在期货市场中，量价分析同样的也有验证价格变动真实性的能力，揭露市场中卖家和买家的真实情绪：</p>
<pre class="mermaid">---
title: 期货市场
---
flowchart LR
A[量价分析] --&gt; B[揭露情绪] --&gt; C[趋势反转时发出信号] --&gt;D[实现对内幕操盘手的跟随]
  </pre>
  <p>这里其实引出了量价分析的核心逻辑：</p>
<ol>
<li>假设内幕操盘者存在</li>
<li>跟随内幕操盘者进行操作</li>
</ol>
<p>在没有真实成交量数据的外汇现货市场，可以使用跳动点数据来做成交量的替代分析工具；跳动点可以按照拍卖报价来理解，报价跳动得越快，说明市场的成交量，活跃程度更高，情绪也更高涨。</p>
<blockquote>
<p>外汇交易市场是内幕操作最多的市场，“汇率战争”这个术语就可以证明。</p>
</blockquote>
<h3 id="volume-rule-利用成交量的方式和基本准则">Volume Rule 利用成交量的方式和基本准则</h3>
<p>在使用成交量的时候，需要注意以下的三个方面：</p>
<ul>
<li>成交量的<strong>大小是相对的</strong>：要考虑均值，也就是相对规模，相对性上的关系才是重中之重；</li>
<li>离开价格谈成交量是毫无意义的</li>
<li>时间也是关键因素之一，</li>
</ul>
<p>下面有一个例子，后面再细细体会：</p>
<ol>
<li>当熊市中市场以较大角度向下运行，而价格如瀑布般暴跌，伴随着巨大成交量，这就是买入高峰；（此时散户由于恐慌大量抛售，而主力正在低价买入，这时对我们而言就是一个机会。）</li>
<li>在牛市的顶点，我们发现成交量急剧放大，那么这就是一个抛售高峰。（主力向散户派发手中的股票，但是散户却认为价格就一步登天）</li>
</ol>
<p>!! 此外作者认为，这是一个&quot;酌情&quot;做出决策的策略，因此<strong>永远不具备自动化实施的可能</strong>，这点我需要质疑一下，看下后面具体的执行方法。</p>



  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>对于投资者和投机者而言，研究成交量的原因是为了洞察内部人士，或者说专业人士的举动，跟随他们的方向。</p>

</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>家庭服务器的具体备份实现</title>
      <link>https://aikenh.cn/posts/%E5%AE%B6%E5%BA%AD%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84%E5%85%B7%E4%BD%93%E5%A4%87%E4%BB%BD%E5%AE%9E%E7%8E%B0/</link>
      <pubDate>Wed, 08 Jan 2025 11:14:30 +0000</pubDate>
      <guid>https://aikenh.cn/posts/%E5%AE%B6%E5%BA%AD%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84%E5%85%B7%E4%BD%93%E5%A4%87%E4%BB%BD%E5%AE%9E%E7%8E%B0/</guid>
      <description>Descript for artical</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>前文中选择了 Kopia 作为笔者的备份工具，本文记录具体的备份执行方案以便后续查阅；</p>

</blockquote>
<h2 id="-备份文件存储位置选择">🌐 备份文件存储位置选择</h2>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231229113137.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231229113137.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231229113137.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>基于笔者的现实条件约束，最终没有完全遵循 3-2-1 去管理自己的备份，而是利用 kopia 以如下的 2-1-1 作为替代：</p>
<ul>
<li>2：除了原始数据，最终有 2 份分处不同位置的备份；</li>
<li>1：使用 kopia 在链接本机的移动 SSD 硬盘上存储第一份备份；</li>
<li>1：使用 kopia 和 Webdav 在阿里云盘上存储加密的第二份备份；</li>
</ul>
<p>此处考虑类似阿里云盘的第三方服务本身做了备份处理，具备一定的容灾能力，因此使用第三方存储服务去做一个备份点就相当于将部分备份任务转嫁出去了。</p>
<p>而对于第三方网盘可能出现的数据泄露的担忧，由于 kopia 本身备份和上传的是加密的内容，无法被直接查看，相当于在平台外还添加了一层隐私安全的保险，不用担心隐私泄露问题。</p>
<h2 id="-备份内容选择">📌 备份内容选择</h2>
<h3 id="immich-的备份和恢复">Immich 的备份和恢复</h3>
<pre class="mermaid">---
title: Immich的备份构成
---
flowchart TD
A[immich Server]--&gt; B[(user-Databse)]
A --&gt; C[(filesystem )]

B --&gt; D[AssertPath]
B --&gt; E[User Info]

C --&gt; F[Origin Assert]
C --donot need backup--&gt; G[Generate Assert]
  </pre>
  <p>受限于 Immich 的机制，文件和用户的关联是在上传过程中建立的，对应的关联信息是存储在数据库中（上图的 user-Database）<span class="sidenote-number"><small class="sidenote"><a href="https://immich.app/docs/administration/backup-and-restore/" target="_blank" rel="noopener">backup-and-restore</a></small></span>，如果仅对原始的 Assets 进行备份，<strong>没有备份数据库的话，会导致无法将图片和账号进行绑定，就会需要重新对大量的图片数据重新走上传/外部库导入流程</strong>；</p>
<p>重复的上传/外部库流程由于 1. 导入服务端原有的图片；2. 移动端设备的自动上传；会导致<strong>出现大量的重复图片</strong>，增加存储负担和查看体验；再加上其本身带来的<strong>时间和性能消耗</strong>，是非常得不偿失的。</p>
<p>如果不幸陷入了此等境地，上传建议使用<strong>外部库</strong><span class="sidenote-number"><small class="sidenote"><a href="https://immich.app/docs/features/libraries" target="_blank" rel="noopener">External Library</a></small></span>的方式来导入原有文件夹，这样可以迅速的对多个用户的多个目录去处理，然后等待其后台处理完毕；</p>
<h4 id="标准备份流程">标准备份流程</h4>
<p>言归正传，接下来分别介绍一下基于 Kopia 如何去实现一个正常的备份流程：</p>
<pre class="mermaid">---
title: 一、Kopia 备份Immich User-Dataset
---
flowchart LR

A[Immich] --&gt; B[AutoBackup-Process]
A --&gt; C[optional: Manual Backup Process]

B --&gt; D[Kopia Backup Process]
C --&gt; D
  </pre>
  <p>也就是说只需要在当天的<strong>数据库备份之后启动 kopia 对 immich 的备份任务</strong>即可，无论是定时的自动备份还是手动备份；</p>
<blockquote>
<p>为了便于备份，新版本的 Immich 每天会自动生成数据库的备份到 <code>UPLOAD_LOCATION/backups</code> 目录中</p>
</blockquote>
<p>手动备份的指令如下，执行手动任务的话可以使用 crontab 定时：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker <span class="nb">exec</span> -t immich_postgres pg_dumpall --clean --if-exists --username<span class="o">=</span>postgres <span class="p">|</span> gzip &gt; <span class="s2">&#34;/path/to/backup/dump.sql.gz&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>二、备份完数据库后，仅需备份/恢复对应的<strong>原始资源文件夹</strong>即可，原始资源文件夹如下：</p>
<ol>
<li><code>UPLOAD_LOCATION/library</code></li>
<li><code>UPLOAD_LOCATION/upload</code></li>
<li><code>UPLOAD_LOCATION/profile</code></li>
</ol>
<p>具体不同类别的存放路径会基于是否开启了 <code>Storage template</code> 有一些细微的区别<span class="sidenote-number"><small class="sidenote">参见 <a href="https://immich.app/docs/administration/backup-and-restore/#asset-types-and-storage-locations" target="_blank" rel="noopener">asset-types-and-storage-locations</a></small></span></p>
<p><strong>也就是说，只需要在指定的系统备份时间之后，启动 kopia 备份，并包含上述提到的 4 个目录，即可实现对 immich server 的充分备份。</strong></p>
<h4 id="标准还原流程">标准还原流程</h4>
<pre class="mermaid">---
title: 还原immich资源和设置
---
flowchart LR
A[(&#34;Kopia
Snapshort&#34;)] --&gt; B[&#34;Restore 
					Assert 
					Organize&#34;]
B --&gt; C[CreateImmich 
		WithoutRun]
C --&gt; D[Restore 
		Datast]
D --&gt; E[&#34;Run 
		 Immich&#34;] --update backup path--&gt; A
  </pre>
  <p>简而言之，这里最主要需要注意的就是在构建 Immich 之后，正式运行之前，就需要执行数据库的还原，避免运行后和生成的新数据库出现键值等的冲突；</p>
<blockquote>
<p>这里资产的位置还原可能没有说那么紧急，但是如果需要修改资产在 Upload_location 中的位置的话，可能需要手动对备份的数据库进行修改，不建议。</p>
</blockquote>
<p>还原脚本如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker compose down -v  <span class="c1"># CAUTION! Deletes all Immich data to start from scratch</span>
</span></span><span class="line"><span class="cl"><span class="c1">## Uncomment the next line and replace DB_DATA_LOCATION with your Postgres path to permanently reset the Postgres database</span>
</span></span><span class="line"><span class="cl"><span class="c1"># rm -rf DB_DATA_LOCATION # CAUTION! Deletes all Immich data to start from scratch</span>
</span></span><span class="line"><span class="cl">docker compose pull             <span class="c1"># Update to latest version of Immich (if desired)</span>
</span></span><span class="line"><span class="cl">docker compose create           <span class="c1"># Create Docker containers for Immich apps without running them</span>
</span></span><span class="line"><span class="cl">docker start immich_postgres    <span class="c1"># Start Postgres server</span>
</span></span><span class="line"><span class="cl">sleep <span class="m">10</span>                        <span class="c1"># Wait for Postgres server to start up</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Check the database user if you deviated from the default</span>
</span></span><span class="line"><span class="cl">gunzip &lt; <span class="s2">&#34;/path/to/backup/dump.sql.gz&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span><span class="p">|</span> sed <span class="s2">&#34;s/SELECT pg_catalog.set_config(&#39;search_path&#39;, &#39;&#39;, false);/SELECT pg_catalog.set_config(&#39;search_path&#39;, &#39;public, pg_catalog&#39;, true);/g&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span><span class="p">|</span> docker <span class="nb">exec</span> -i immich_postgres psql --username<span class="o">=</span>postgres  <span class="c1"># Restore Backup</span>
</span></span><span class="line"><span class="cl">docker compose up -d            <span class="c1"># Start remainder of Immich apps</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>上面注释掉的 <code>rm -rf DB_DATA_LOCATION # CAUTION! Deletes all Immich data to start from scratch</code> 这一行就是在并非初次启动 Immich 的时候执行时，如果遇到 Postgres 的冲突，才需要执行，通过直接删除数据库来还原初始状态。</p>
<p>恢复后记得修改自己的 Kopia 中 immich 的新路径。</p>
<h3 id="docker-volume-的备份和恢复">Docker Volume 的备份和恢复</h3>
<p><a href="https://sealhuang.github.io/migrate-docker-volume-from-one-host-to-another" target="_blank" rel="noopener">如何对Docker的volume文件在主机间迁移 | sealhuang&rsquo;s blog</a>
</p>
<h3 id="linkstack-的备份和恢复">Linkstack 的备份和恢复</h3>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20250206202410.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20250206202410.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20250206202410.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="-kopia-设置">⚙️ Kopia 设置</h2>
<h3 id="basic-setting-基础设置">Basic Setting 基础设置</h3>
<ul>
<li>设置备份时间和频率</li>
<li>其他的使用默认的即可</li>
</ul>
<h3 id="kopia-连接阿里云盘">Kopia 连接阿里云盘</h3>
<p>要将阿里云盘作为 Kopia 的一个备份仓库，需要使用 Webdav 去使得 Kopia 连接阿里云盘，但是由于阿里云盘官方第三方服务包提供的 <strong>Webdav 仅支持文件的读取，并不支持文件的写入</strong>，因此官方的 webdav 服务无法满足该需求；</p>
<ul>
<li>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/2761737431201_.pic.jpg">
    <img alt="2761737431201_.pic.jpg" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/2761737431201_.pic.jpg"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/2761737431201_.pic.jpg" style="display: block; margin: 0 auto;"
      alt="2761737431201_.pic.jpg"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</li>
</ul>
<p>因此需要使用开源的第三方服务来挂载阿里云盘，并通过第三方服务映射出来的较为完备的 webdav 功能来连接 kopia ，进而使其作为存储仓库；这里有较多的选择，可以自行查阅其他选择，此处笔者使用的是家庭服务中提及的 <strong><a href="https://alist.nn.ci/zh/guide/webdav.html" target="_blank" rel="noopener">Alist</a>
</strong>，下面简单介绍一下相关的参数配置：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">基于ip的url: https://{ip}:{port}/dav/{specific_path}
</span></span><span class="line"><span class="cl">基于domain的url: https://{domain}/dav/{specific_path}
</span></span><span class="line"><span class="cl">基于二级域名alist的url: https://{domain}/alist/dav/{specific_dirctory_path}</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>账号和密码同 Alist 的登录账号名和密码即可</p>
]]></content:encoded>
    </item>
    <item>
      <title>基于Github部署和发布Hugo博客</title>
      <link>https://aikenh.cn/posts/%E5%8F%91%E5%B8%83%E5%92%8C%E9%83%A8%E7%BD%B2hugo%E5%8D%9A%E5%AE%A2/</link>
      <pubDate>Thu, 19 Dec 2024 11:35:08 +0000</pubDate>
      <guid>https://aikenh.cn/posts/%E5%8F%91%E5%B8%83%E5%92%8C%E9%83%A8%E7%BD%B2hugo%E5%8D%9A%E5%AE%A2/</guid>
      <description>通过 GithubPage 或者 Vercel, Netlify 发布 Hugo 博客的记录</description>
      <content:encoded><![CDATA[<h2 id="托管平台选择">托管平台选择</h2>
<p>一些常见的托管平台 PaaS <span class="sidenote-number"><small class="sidenote">Platform as a Service <a href="https://cloud.google.com/learn/what-is-paas?hl=zh-CN" target="_blank" rel="noopener">平台及服务</a>
，旨在使用户专注于应用代码开发</small></span> 的免费情况如下；</p>
<table>
  <thead>
      <tr>
          <th style="text-align: center">Site</th>
          <th>Github Page</th>
          <th><a href="https://vercel.com/" target="_blank" rel="noopener">Vercel</a>
</th>
          <th><a href="https://www.netlify.com/" target="_blank" rel="noopener">Netfily</a>
</th>
          <th>Coolify</th>
          <th><a href="https://zeabur.com/" target="_blank" rel="noopener">Zeabur</a>
</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: center">Free?</td>
          <td>Y</td>
          <td>Y</td>
          <td>Y</td>
          <td>自托管免费</td>
          <td>N（月费外无需额外）</td>
      </tr>
      <tr>
          <td style="text-align: center">Auto <br>Re-Deployed</td>
          <td>Y</td>
          <td>Y</td>
          <td>Y</td>
          <td>-</td>
          <td>-</td>
      </tr>
  </tbody>
</table>
<p>其实对于这些小型的静态网页的项目部署，大多都是免费的，整体部署的流程也是相对简单，选择一个顺眼，便于国内访问用即可，但是无论是哪个方案，都建议绑定一下自己的域名，一来是更便于记，二来也能便于国内访问。</p>



  
  

<blockquote class="alert-blockquote alert-todo">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Todo</span>
  </p>
  <p>了解一下 Coolify，是否是类似一个公网转发平台的方案，将特定端口的服务使用 Coolify 转发到公网上，然后可以绑定自己的域名，这样的话也不失为一个好东西，我之前的服务也就都能部署出去了；</p>

</blockquote>
<p>最终选择的时候可以考虑以下都是谁在访问自己的博客，然后测一下对应地区平台访问的速度来做决定，国内的话 vercel 好像是被 DNS 污染了，如果要部署在 Vercel 上的的话，考虑在域名解析的地方更换为CF 的解析服务 <span class="sidenote-number"><small class="sidenote">原因：<a href="https://www.zhongfw.online/posts/%E3%80%90%E5%A4%9A%E5%9B%BE%E9%A2%84%E8%AD%A6%E3%80%91vercel%E9%83%A8%E7%BD%B2%E5%8F%8A%E5%9B%BD%E5%86%85%E8%AE%BF%E9%97%AE.html" target="_blank" rel="noopener">【多图预警】vercel部署及国内访问 | VuePress Theme Gungnir</a>

具体方案：<a href="https://www.didispace.com/article/richang/20230917-vercel-china-dns.html" target="_blank" rel="noopener">一招解决Vercel站点在国内无法访问的问题 | 程序猿DD</a>
 | <a href="https://juejin.cn/post/7301193497247727652" target="_blank" rel="noopener">如何在国内访问vercel部署应用？我个人觉得vercel是做前端的大家都应该去了解并且掌握的一个非常方便的部署工具，能 - 掘金</a>
  ；</small></span></p>
<h2 id="直接使用-public-文件夹进行部署">直接使用 Public 文件夹进行部署</h2>
<p>作为静态网页生成器，hugo 通过部署模式生成的 <code>public</code> 文件夹可以很轻松的在包括 <a href="https://docs.github.com/zh/pages/quickstart" target="_blank" rel="noopener">Github pages</a>
 和 <a href="https://vercel.com/" target="_blank" rel="noopener">Vercel</a>
 等第三方平台上的各个托管平台进行部署，部署起来相当简单，只需要将 Publish 文件夹推到github 上，后面的都比较简单了</p>
<ul>
<li>Github Page 直接在Setting-Pages 中设置选择源 Branch 即可，不需手动去写Github Action；</li>
<li>Vercel, Netfily 也是直接绑定对应的Github 仓库的指定分支即可，framework 选择Other；</li>
</ul>
<p>且均能根据 Publish 的变更对网页重新构建，这里就不再赘述。</p>
<h2 id="基于源码直接部署">基于源码直接部署</h2>
<p>基于源码部署主要是考虑到同时将博文本身推送上去，一是使用 git 做版本管理，二是可以不再额外管理一个仓库；因此也可以采用此种方式；</p>
<p>但实际上如果要和本地的 Editor 如 Obsidian 做无缝集成的话，还是会需要一些额外的脚本去做处理，包括写完后自动更新 repo 和推送这些，后续如果笔者记得的话可能也会更新一下相应的脚本；</p>
<h3 id="部署到-github-page">部署到 Github Page</h3>
<p>参考 <a href="https://gohugo.io/hosting-and-deployment/hosting-on-github/" target="_blank" rel="noopener">hugo官方教程</a>
使用 Github Action 进行在线构建和实现 Github Page 的发布，修改其中自己需要进行构建的分支名称和部署命令等，然后直接 push 上去即可。</p>
<p>这里我对部署命令的修改部分如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">  hugo \
</span></span></span><span class="line"><span class="cl"><span class="sd">    --gc \
</span></span></span><span class="line"><span class="cl"><span class="sd">    --minify \
</span></span></span><span class="line"><span class="cl"><span class="sd">    --environment papermod \
</span></span></span><span class="line"><span class="cl"><span class="sd">    --baseURL &#34;${{ steps.pages.outputs.base_url }}/&#34;  </span><span class="w">  </span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>使用非 Master 分支进行构建可能会遇到以下的问题（build 成功，deploy 部分显示如下错误）</p>



  
  

<blockquote class="alert-blockquote alert-error">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Error</span>
  </p>
  <p>Branch &ldquo;x&rdquo; is not allowed to deploy to github-pages due to environment protection rules.</p>

</blockquote>
<p>解决方案：<a href="https://github.com/orgs/community/discussions/39054" target="_blank" rel="noopener">Github community · Discussion #39054</a>
 ，Repo 的 Setting 中找到 Environments 中的 github-pages 项中的 <code>Deployment branches and tags</code> 新增自己想要部署的分支即可；</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212011338.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212011338.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212011338.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>



  
  

<blockquote class="alert-blockquote alert-error">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Error</span>
  </p>
  <p>Static 中的资源加载出现 404，导致界面表现不合预期的情况</p>

</blockquote>
<p>此外，如果个人之前已经对其他的 GithubPage 绑定了域名（例如 <a href="http://aikenh.cn/" target="_blank" rel="noopener">http://aikenh.cn/</a>
 ），这样可能会导致由于网页部署在域名的子目录下( <a href="http://aikenh.cn/hugoblog/" target="_blank" rel="noopener">http://aikenh.cn/hugoblog/</a>
 )，导致一些资源的 url 绑定到域名上（资源被绑定到 <a href="http://aikenh.cn/" target="_blank" rel="noopener">http://aikenh.cn/</a>
 中导致 404 ），无法获取到，这里的解决方式是，通过绑定子域名/二级域名 或者新的域名。</p>
<p>这里简单讲一下子域名的添加 <span class="sidenote-number"><small class="sidenote"><a href="https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site#configuring-a-subdomain" target="_blank" rel="noopener">Github Docs</a></small></span> ，首先在 Github-Repo-Setting-Pages 中设置 Custom domain 如下</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212111721.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212111721.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212111721.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>添加后去自己的域名控制台添加对应的 cname 子域名记录，然后稍后即可</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212111655.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212111655.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212111655.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>添加子域名解析后可能会发现反而 CSS 等样式表加载不出来的问题（上一步的时候没问题），这时候就要考虑是不是 BaseURL 忘记更新了；记得修改项目配置（非 GithubAction 配置）中自己的 baseURL 再推上去使其重新构建，避免存在部分解析问题即可；</p>
<h3 id="部署到其他-paas">部署到其他 PaaS</h3>



  
  

<blockquote class="alert-blockquote alert-error">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Error</span>
  </p>
  <p>由于我们本地开发使用的 Git Submodule 中的地址通常是 git@github ,可能会导致第三方平台在拉取 Submodule 的时候出现一些权限错误导致拉取失败</p>

</blockquote>
<p>因此当我们部署 Netlify 之前可以按照下面的方式更新 Submodule 为 http 链接，首先更改 <code>.gitmodules</code> 中子模块的URL</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="k">[submodule &#34;themes/PaperMod&#34;]</span>
</span></span><span class="line"><span class="cl">  <span class="na">path</span> <span class="o">=</span> <span class="s">themes/PaperMod
</span></span></span><span class="line"><span class="cl"><span class="s">  url = https://github.com/AikenH/papermod-sidebar.git</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>然后执行下列命令来更新子模块的URL</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git submodule sync
</span></span><span class="line"><span class="cl">git submodule update --init --recursive</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>更新完以后将其推送到部署分支，例如 <code>netlify</code></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git checkout -b netlify
</span></span><span class="line"><span class="cl">git add . 
</span></span><span class="line"><span class="cl">git commit -m <span class="s2">&#34;[Conf] update submodule for third-party deploy&#34;</span>
</span></span><span class="line"><span class="cl">git push origin netlify:netlify</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="部署到-netlify">部署到 Netlify</h4>
<p><strong>做完上述 Submodule 的准备之后</strong>，在 Netlify 的dashboard 上导入Repo 进行发布：</p>
<ul>
<li>导入仓库，选择好发布的分支</li>
</ul>
<p>可以参考下列命令来设置自己的发布参数以及环境变量（hugo 版本）</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212142429.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212142429.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212142429.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>环境变量的Key-Value 分别为：HUGO_VERSION 还有你本地的 hugo 版本，可以通过下列命令获取</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">hugo version</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>域名绑定：主要是参考官方指引，将需要的域名填入后，按照如下指引，在购买域名处添加CName 即可；</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212171616.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212171616.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212171616.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>随后记得更新网站的 BaseURL 以便网站正常工作;</p>
<h4 id="部署到-vercel">部署到 Vercel</h4>
<p><strong>做完上述 Submodule 的准备之后</strong>，同样在 Vercel 处的设置也是比较简单的，导入指定的仓库后，将模版指定为Hugo，并修改部署配置如下：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212144416.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212144416.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212144416.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>同样添加环境变量：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212144450.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212144450.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212144450.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>但是 Vercel 中指定分支的方式相对较麻烦一些，在部署后，进入project 的dashboard 中，选择Setting</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212144613.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212144613.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212144613.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>其中的 Git -&gt; Production 跳转到指定页面去设置分支，设置完记得选择保存，同时下面有个环境变量也可以在设置一次。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212144707.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212144707.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212144707.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212144752.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212144752.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212144752.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>到此为止的话其他分支上的提交也会导致触发build，为此我们还需要进一步设置，在刚刚 Git 页面的最底下，选择 only build production 即可，这里参考 <span class="sidenote-number"><small class="sidenote"><a href="https://oragekk.me/tutorial/CI_CD/vercel-deploy.html#_2-%E6%AD%A5%E9%AA%A4" target="_blank" rel="noopener">oragekk</a></small></span> ：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212173248.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212173248.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212173248.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>后面再触发一次 Deploy 任务以后就可以看到分支切换到指定的分支即可</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212144841.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212144841.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241212144841.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>添加域名：待补充；</p>
<h2 id="troubleshooting-问题解决">TroubleShooting 问题解决</h2>
<h3 id="部署时-css-样式不显示问题">部署时 CSS 样式不显示问题</h3>
<p>hugo 部署时遇到像 CSS 和 JS 或者图像等不显示的问题，可能有以下的两种原因：</p>
<p>一、假如图像, JS, CSS 都不显示，可以通过浏览器的开发者模式中的网络选项等去检查资源的对应地址是否是正确的，然后检查 hugo.yaml 中的 <code>base_url</code> 是否设置正确；</p>
<p>二、假如仅 CSS 不显示，只显示图像和文字，可以打开开发者模式中的控制台，看是否有如下报错：</p>



  
  

<blockquote class="alert-blockquote alert-error">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Error</span>
  </p>
  <p>Failed to find a valid digest in the &lsquo;integrity&rsquo; attribute for resource</p>

</blockquote>
<p>如果是如下报错的话，可能是由于 minify 生成静态网页时，去掉了 html,js,css 等文件的部分空格和格式，来缩小文件的体积，但是修改后会导致文件校验失败，从而阻止加载，因此就会有两种解决方式：</p>
<p><strong>hugo 设置中关闭校验</strong> <span class="sidenote-number"><small class="sidenote"><a href="https://spartanmans.github.io/posts/hugobug/" target="_blank" rel="noopener">bj-Space</a></small></span> : 在 hugo.yaml 中添加，（使用toml 配置的情自行修改对应选项）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">params</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nt">assets</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nt">disableFingerprinting</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>关闭 minify 选项</strong> <span class="sidenote-number"><small class="sidenote"><a href="https://www.333rd.net/zh/posts/tech/hugo%E4%B8%A2%E5%A4%B1css%E5%AF%BC%E8%87%B4%E6%98%BE%E7%A4%BA%E5%BC%82%E5%B8%B8%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3/" target="_blank" rel="noopener">3rd&rsquo;s blog</a></small></span></p>
<p>还有一些其他的可能问题：http 和 https 混用</p>
<h2 id="fi">FI</h2>
]]></content:encoded>
    </item>
    <item>
      <title>利用ShortCode增加Hugo的样式支持</title>
      <link>https://aikenh.cn/posts/%E5%88%A9%E7%94%A8shortcode%E5%A2%9E%E5%8A%A0hugo%E7%9A%84%E6%A0%B7%E5%BC%8F%E6%94%AF%E6%8C%81/</link>
      <pubDate>Wed, 18 Dec 2024 17:15:37 +0000</pubDate>
      <guid>https://aikenh.cn/posts/%E5%88%A9%E7%94%A8shortcode%E5%A2%9E%E5%8A%A0hugo%E7%9A%84%E6%A0%B7%E5%BC%8F%E6%94%AF%E6%8C%81/</guid>
      <description>通过Hugo的短代码功能，拓展主题的功能，使博客能够支持更多的样式</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-important">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0 1 14.25 13H8.06l-2.573 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25Zm7 2.25v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 9a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path>
    </svg>
    <span>Important</span>
  </p>
  <p>本文为了避免 hugo 直接将 shortcode 渲染出来，在所有的 {{ 和 &lt; 或 &gt;，% 之间添加空格，具体使用的时候记得去掉。</p>

</blockquote>
<h2 id="whats-shortcode-in-hugo-mean-啥是简码">What&rsquo;s ShortCode in Hugo Mean 啥是简码</h2>
<p>Hugo 中的短代码 <span class="sidenote-number"><small class="sidenote">后续用简码来表示</small></span> 可以理解成一种使用固定方式引用的 Template(或者说 Alias)，通过使用<strong>预先定义模版</strong>，避免在 markdown 中直接添加大量 html 或者 go templates 代码</p>
<p>通常通过 <code>{{ &lt; shortcode &gt; }}</code> 的方式来调用模版，定义的简码可以为如下的三种形式：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: center">type</th>
          <th>example</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: center">Single-Word ShortCode</td>
          <td><code>{{ &lt; year &gt; }}</code></td>
      </tr>
      <tr>
          <td style="text-align: center">With-Params ShortCode</td>
          <td><code>{{ &lt; img src=&quot;URL&quot; title=&quot;Title&quot; &gt; }}</code></td>
      </tr>
      <tr>
          <td style="text-align: center">Paired ShortCode</td>
          <td><code>{{ &lt; shortcode &gt; }} content {{ &lt; shortcode &gt; }}</code></td>
      </tr>
  </tbody>
</table>
<p>来支持不同类型的模版代码，将一些比较复杂的 html 代码通过简码的形式嵌入，可以使得我们的静态博客支持更多的拓展样式；<a href="https://gohugo.io/content-management/shortcodes/" target="_blank" rel="noopener">官方文档</a>
</p>
<h3 id="benefits-and-limitation-利弊分析">Benefits and Limitation 利弊分析</h3>



  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>简码存在什么好处和弊端，应该在什么时候使用简码，什么情况下定义为简码，什么时候将其定义为内置的渲染类型；</p>

</blockquote>
<p>正如上文所说，ShortCode 其实本质上可以理解为 Hugo 内置的一种模版功能，通过<strong>模版</strong>用于在 Markdown 中快速的调用<strong>额外</strong>的样式，因此优势也就显而易见：</p>
<ul>
<li>模版的角度：简化书写，具备良好的可重用性，统一管理；</li>
<li>拓展的角度：丰富样式，增强功能</li>
</ul>
<p>例如我们可以使用简码为文章添加 sidenote(边注)，可以让文章的主体更加简洁，更为美观，效果如下：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241216150934.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241216150934.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241216150934.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>虽然使用简码确实能够使得 blog 更加的美观，拓展一些额外的功能，但是相应的会使得本地软件编写时的<strong>所见即所得的特性被破坏</strong>，同时对文档或者说<strong>博客平台迁移</strong>的时候也会增加一些额外的工作量对文档进行处理；</p>
<blockquote>
<p>当然这里也可以通过对一些开源的笔记软件进行适配去维持所见即所得的效果，但是工作量的增加是实打实的；</p>
</blockquote>
<p>为此，退而求其次的，为了保持原 markdown 的可迁移的特性不要被严重破坏，同时能够较好的维持所见即所得的可以考虑使用一下的流程去处理<small> 笔者使用 Obsidian 编写文档</small>：</p>
<pre class="mermaid">---
title: 文档处理流程
---
flowchart LR
	subgraph source
		MD[&#34;Md + ez-HTML&#34;]
		Obs[&#34;Obsidian&#34;] --- MD
	end
	subgraph Publish
		Pub[&#34;Publish Dir&#34;]
		Hugo[&#34;Hugo&#34;] --- Pub
	end
	source --Cond--&gt; Scr[&#34;Convert Md&#34;]
	Scr --&gt; Publish
	Publish --&gt; Tri[&#34;Tiggle Publish&#34;]	
  </pre>
  <p>在源文件中尽可能的使用原生的 markdown 和一些简单的 html 去编写，然后触发转换脚本之后，根据各种不同的条件（例如发布平台）去进行 markdown 的转换（html 转换为短代码，或删除多余部分）并发布到对应的路径上去触发发布任务；</p>
<p>以边注为例，这里可以使用 <code>&lt;small&gt; content &lt;small&gt;</code> 在 Obsidian 中显示其脚注的特性，然后当发布到 Hugo 的时候，利用脚本将 <code>small</code> 转换为 <code>sidenote</code> 的形式即可，这里替换起来还是很简单的；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">re</span>
</span></span><span class="line"><span class="cl"><span class="n">content</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="sa">r</span><span class="s1">&#39;&lt;small&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;&lt;sidenote&gt;&#39;</span><span class="p">,</span> <span class="n">content</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">content</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="sa">r</span><span class="s1">&#39;&lt;/small&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;&lt;/sidenote&gt;&#39;</span><span class="p">,</span> <span class="n">content</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>整体而言，笔者认为尽量少用那些比较特异的样式来破坏 markdown 的所见即所得的特性，但是可以通过这这种简单的 html 格式来保持的倒是无所谓，像是一些时间轴之类的，或者一些比较复杂的样式，建议还是少用，或者在一些场景将其转换为图片嵌入，主要的部分还是要让博客回归内容本身；</p>
<h3 id="some-default-shortcode-默认简码">Some Default ShortCode 默认简码</h3>
<p>hugo 本身支持了部分的 ShortCode，这里简单列举记录，便于需要的时候调用，同时避免重复造轮子：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: center">Name</th>
          <th>Example</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: center">Gist</td>
          <td><a href="https://gist.github.com/spf13/7896402" target="_blank" rel="noopener"><code>{{ &lt; gist spf13 7896402 &gt; }}</code></a>
</td>
      </tr>
      <tr>
          <td style="text-align: center">Ins</td>
          <td><a href="https://www.instagram.com/p/CxOWiQNP2MO/" target="_blank" rel="noopener"><code>{{ &lt; instagram CxOWiQNP2MO &gt; }}</code></a>
</td>
      </tr>
      <tr>
          <td style="text-align: center">Twitter</td>
          <td><a href="https://x.com/SanDiegoZoo/status/1453110110599868418" target="_blank" rel="noopener"><code>{{ &lt; twitter user=&quot;SanDiegoZoo&quot; id=&quot;1453110110599868418&quot; &gt; }}</code></a>
</td>
      </tr>
      <tr>
          <td style="text-align: center">Youtube</td>
          <td><a href="https://www.youtube.com/watch?v=0RKpf3rK57I" target="_blank" rel="noopener"><code>{{ &lt; youtube 0RKpf3rK57I &gt; }}</code></a>
</td>
      </tr>
  </tbody>
</table>
<p>这些具体的参数或者更多默认的一些 Shortcode 可以去<a href="https://gohugo.io/content-management/shortcodes/" target="_blank" rel="noopener">官网</a>
 查阅，这里就不在多说。</p>
<h3 id="how-to-design-a-shortcode-编写简码">How To Design a ShortCode 编写简码</h3>
<p>主要的流程如下，如果需要自己定义，建议还是去<a href="https://gohugo.io/templates/shortcode/" target="_blank" rel="noopener">官网</a>
查看详细的文档、参数和优先级说明。</p>
<p>一、创建简码文件</p>
<p>在 Hugo 项目的 <code>layout/shortcodes</code> 中新建 <code>【keyword】.html</code> 文件，这里文件名的 keyword 会成为后续调用简码时的关键词；</p>
<p>二、编写简码文件</p>
<p>使用 Go template 和 html 编写你所需要的拓展样式，并通过 Go template 获取调用简码时传入的<strong>内容和参数</strong>进行处理和渲染；</p>
<p>下面简单列一些获取采位置参数，设定参数的写法：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>go</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="p">{{</span> <span class="p">.</span><span class="nx">Get</span> <span class="s">&#34;class&#34;</span> <span class="p">}}</span>
</span></span><span class="line"><span class="cl"><span class="p">{{</span> <span class="p">.</span><span class="nx">Get</span> <span class="mi">0</span> <span class="p">}}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>获取 Paired 中填写的内容则可以使用 <code>.Inner</code> 去获取，如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>go</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="p">{{</span> <span class="k">if</span> <span class="nx">strings</span><span class="p">.</span><span class="nx">ContainsNonSpace</span> <span class="p">.</span><span class="nx">Inner</span> <span class="p">}}</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Inner</span> <span class="nx">is</span> <span class="nx">not</span> <span class="nx">empty</span>
</span></span><span class="line"><span class="cl"><span class="p">{{</span> <span class="nx">end</span> <span class="p">}}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>更多参数和内置变量和方法请参见官网文档和说明。</p>
<p>三、调用简码</p>
<p>使用 <code>{{ &lt; keyword &gt; }}</code> 或者 <code>{{ % keyword % }}</code> 的方式，或是上述提及的 paired 的方式进行调用。</p>
<h2 id="what-i-support-in-my-website">What I Support In My Website</h2>



  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>本章节主要分享&amp;感谢一些本博客中使用的短代码的来源，并简单介绍部分我修改或者编写的短代码，包括加密还有边注的短代码；</p>

</blockquote>
<p>主题中引入的大部分 Shortcode 来自以下几位博主，这里简单整理了一下，这里就不再重复，如果需要的话可以转到博主的文章中查看，感谢几位博主的分享!!：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: center">author</th>
          <th>shortcodes</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: center"><a href="https://guanqr.com/tech/website/hugo-shortcodes-customization/" target="_blank" rel="noopener">荷载独彷徨</a>
</td>
          <td>文字对齐、github 卡片、notice(两种)、quote(两种)</td>
      </tr>
      <tr>
          <td style="text-align: center"><a href="https://www.xalaok.top/post/hugo-shortcodes/" target="_blank" rel="noopener">Naive koala</a>
</td>
          <td>Notice、隐藏内容、聊天气泡、时间轴、友联、块引用、bilibili、腾讯视频</td>
      </tr>
      <tr>
          <td style="text-align: center"><a href="https://blog.imych.one/hugo-shortcodes-iframe/" target="_blank" rel="noopener">YC Photography</a>
</td>
          <td>iframe</td>
      </tr>
      <tr>
          <td style="text-align: center"><a href="https://kdjlyy.github.io/posts/site/hugo_shortcodes/" target="_blank" rel="noopener">向着悠远的苍穹</a>
</td>
          <td>PPT、PDF、博客内链、代码折叠</td>
      </tr>
  </tbody>
</table>
<blockquote>
<p>部分博主使用的是 Scss，使用的时候可以去网上搜索一下 Scss 转 css 的去转换成自己熟悉的格式，再根据自己主题的配色和习惯去简单调整一下 css 样式即可。</p>
</blockquote>
<p>接下来介绍一下自己修改或者编写的一些简码，这里也分享出来供大家参考：</p>
<h3 id="sidenote-边注简码">Sidenote 边注简码</h3>
<p>笔者希望博客能够充分利用视区的宽度，因此将 Papermod 的 Nav 和 Toc 都改到了侧边，但是通常使用宽屏阅读的时候，感觉还是有一部分空间没有被利用，决定通过简码支持 MarginNote <span class="sidenote-number"><small class="sidenote">这里受<a href="https://yunpengtai.top/posts/hello-world/" target="_blank" rel="noopener">台运鹏</a>
 该博客的启发，感谢其分享</small></span></p>
<p>最终参考 KF <span class="sidenote-number"><small class="sidenote"><a href="https://kennethfriedman.org/thoughts/2019/marginal-notes/" target="_blank" rel="noopener">KF: Marginal Notes</a></small></span>  和 a Scripter <span class="sidenote-number"><small class="sidenote"><a href="https://scripter.co/sidenotes-using-only-css/" target="_blank" rel="noopener">Sidenotes using only CSS ❚ A Scripter&rsquo;s Notes</a></small></span>  的实现，编写 hugo 的 shortcode，其核心就在于</p>
<ul>
<li>使用 relative 和 float 进行 postion 控制</li>
<li>然后通过-值的 margin 来校准位置</li>
<li>考虑响应式的要素再去启用侧边注释，否则就嵌入正文中</li>
<li>使用 counter 做脚注</li>
</ul>
<p>最终 shortcode 在本博客中呈现的效果和对应的 html 和 css 如下：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217154653.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217154653.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217154653.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217154717.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217154717.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217154717.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217154801.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217154801.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217154801.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;sidenote-number&#34;</span><span class="p">&gt;&lt;</span><span class="nt">small</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;sidenote&#34;</span><span class="p">&gt;</span>{{ .Inner | markdownify }}<span class="p">&lt;/</span><span class="nt">small</span><span class="p">&gt;&lt;/</span><span class="nt">span</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">sidenote</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-size</span><span class="p">:</span> <span class="mi">80</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">position</span><span class="p">:</span> <span class="kc">relative</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c">/* Wide viewport */</span>
</span></span><span class="line"><span class="cl"><span class="p">@</span><span class="k">media</span> <span class="o">(</span><span class="nt">min-width</span><span class="o">:</span> <span class="nt">1500px</span><span class="o">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nc">sidenote</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">float</span><span class="p">:</span> <span class="kc">left</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">clear</span><span class="p">:</span> <span class="kc">left</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">margin-left</span><span class="p">:</span> <span class="mi">-16</span><span class="kt">vw</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">text-align</span><span class="p">:</span> <span class="kc">right</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">top</span><span class="p">:</span> <span class="mi">0</span><span class="kt">rem</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">width</span><span class="p">:</span> <span class="mi">13</span><span class="kt">vw</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">margin-top</span><span class="p">:</span> <span class="mi">1</span><span class="kt">rem</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">border-top</span><span class="p">:</span> <span class="mi">2</span><span class="kt">px</span> <span class="kc">solid</span> <span class="nb">rgb</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">sidenote</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">border-top</span><span class="p">:</span> <span class="mi">2</span><span class="kt">px</span> <span class="kc">solid</span> <span class="nb">rgb</span><span class="p">(</span><span class="mi">255</span><span class="p">,</span> <span class="mi">98</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c">/* Sidenote counter */</span>
</span></span><span class="line"><span class="cl"><span class="nt">main</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">counter-reset</span><span class="p">:</span> <span class="n">sidenote-counter</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">sidenote-number</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">counter-increment</span><span class="p">:</span> <span class="n">sidenote-counter</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c">/* Counter before the sidenote in the margin. */</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">sidenote</span><span class="p">::</span><span class="nd">before</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">content</span><span class="p">:</span> <span class="nb">counter</span><span class="p">(</span><span class="n">sidenote</span><span class="o">-</span><span class="n">counter</span><span class="p">)</span> <span class="s2">&#34;.&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">position</span><span class="p">:</span> <span class="kc">relative</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">vertical-align</span><span class="p">:</span> <span class="kc">baseline</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-size</span><span class="p">:</span> <span class="mf">0.9</span><span class="kt">em</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-weight</span><span class="p">:</span> <span class="kc">bold</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c">/* Counter in the main body. */</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">sidenote-number</span><span class="p">::</span><span class="nd">after</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">content</span><span class="p">:</span> <span class="nb">counter</span><span class="p">(</span><span class="n">sidenote</span><span class="o">-</span><span class="n">counter</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">vertical-align</span><span class="p">:</span> <span class="kc">super</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-size</span><span class="p">:</span> <span class="mf">0.7</span><span class="kt">em</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-weight</span><span class="p">:</span> <span class="kc">bold</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">margin-right</span><span class="p">:</span> <span class="mf">0.5</span><span class="kt">rem</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">@</span><span class="k">media</span> <span class="o">(</span><span class="nt">min-width</span><span class="o">:</span> <span class="nt">1400px</span><span class="o">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* Highlight the sidenote when mouse hovers on the sidenote number in body. */</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nc">sidenote-number</span><span class="p">:</span><span class="nd">hover</span> <span class="p">.</span><span class="nc">sidenote</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kp">-webkit-</span><span class="n">backdrop-filter</span><span class="p">:</span> <span class="nb">blur</span><span class="p">(</span><span class="mi">30</span><span class="kt">px</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">backdrop-filter</span><span class="p">:</span> <span class="nb">blur</span><span class="p">(</span><span class="mi">30</span><span class="kt">px</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">background-color</span><span class="p">:</span> <span class="mh">#ffffff</span><span class="mi">7</span><span class="n">a</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">border-radius</span><span class="p">:</span> <span class="mi">5</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">font-weight</span><span class="p">:</span> <span class="kc">bold</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">padding</span><span class="p">:</span> <span class="mi">5</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">box-shadow</span><span class="p">:</span> <span class="mi">5</span><span class="kt">px</span> <span class="mi">5</span><span class="kt">px</span> <span class="mi">10</span><span class="kt">px</span> <span class="nb">rgb</span><span class="p">(</span><span class="mi">25</span><span class="p">,</span> <span class="mi">25</span><span class="p">,</span> <span class="mi">25</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">                <span class="mi">-5</span><span class="kt">px</span> <span class="mi">-5</span><span class="kt">px</span> <span class="mi">10</span><span class="kt">px</span> <span class="nb">rgb</span><span class="p">(</span><span class="mi">60</span><span class="p">,</span> <span class="mi">60</span><span class="p">,</span> <span class="mi">60</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">sidenote-number</span><span class="p">:</span><span class="nd">hover</span> <span class="p">.</span><span class="nc">sidenote</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">background-color</span><span class="p">:</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">sidenote-number</span> <span class="nt">small</span><span class="p">.</span><span class="nc">sidenote</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">sidenote-number</span> <span class="nt">small</span><span class="p">.</span><span class="nc">sidenote</span> <span class="nt">a</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="nb">rgb</span><span class="p">(</span><span class="mi">255</span><span class="p">,</span> <span class="mi">179</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">sidenote-number</span> <span class="o">+</span> <span class="nt">p</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="kc">inline</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">p</span><span class="p">:</span><span class="nd">has</span><span class="o">(+</span> <span class="p">.</span><span class="nc">sidenote-number</span><span class="o">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="kc">inline</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>也遇到了一些小问题：</p>



  
  

<blockquote class="alert-blockquote alert-error">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Error</span>
  </p>
  <p>counter 计数混乱</p>

</blockquote>
<p>一开始使用 body 去做 counter-reset ，后续改为 main 去做 counter-reset 后就好，没有找到中间哪里触发了 body 的 reset，如果有了解的希望指点一二，感恩；</p>
<p>还有一些其他可以借鉴的 MarginNote 的实现如下，感兴趣的大家可以去看看：</p>
<ul>
<li><a href="https://fanrongbin.com/blog-theme-changed/" target="_blank" rel="noopener">Rongbin&rsquo;s Blog</a>
</li>
<li><a href="https://dongheenam.info/posts/hugo-sidenotes/" target="_blank" rel="noopener">Sidenotes in Hugo | dongheenam.info</a>
</li>
</ul>
<h3 id="encrypt-加密简码实践">Encrypt 加密简码实践</h3>
<p>由于博客难免会写一些只想自己看或者说，只想和朋友分享的内容，因此在之前的 hexo 中支持了加密的功能，于是在 hugo 上找替代品的时候，目前发现的都是需要外部的代码|二进制执行，或是使用 submodule，这里为了更简单一些就尝试将其改为简码的模式；</p>
<p>参考 <a href="https://github.com/Li4n0/hugo_encryptor/tree/master?tab=readme-ov-file" target="_blank" rel="noopener">Li4n0的hugo_encryptor</a>
 借助 Gpt4o 将其改为纯 html+js 的形式，由此实现利用简码对文章加密，效果如下：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217111719.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217111719.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217111719.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217111733.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217111733.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217111733.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>但是这个方法的加密实际上是一个<strong>伪加密</strong>，存在以下的问题：</p>
<ol>
<li>一篇文章仅能加密一次，否则会使得密码出错;</li>
<li>无法加密源文件，文章的内容仍能通过开发者模式中的源文件进行查看<strong>未加密的 html</strong>，只是无法直观的获取。</li>
</ol>
<blockquote>
<p>这是由于该脚本仅仅是对加载过程中的网页进行加密，但是对对应的 html 内容是没有加密的</p>
</blockquote>
<p>这是由于 hugo 静态站点生成的本质，如果需要完全的加密的话，可能还是要考虑外部对生成的 html 进行处理，或者看能不能想办法干预 hugo 本身生成静态文件的过程，这里由于笔者本身对相应的技术栈还不是特别熟悉，因此暂且搁置。</p>
<p>这里还尝试了 <a href="https://github.com/Li4n0/hugo_encryptor/tree/master?tab=readme-ov-file" target="_blank" rel="noopener">Li4n0的hugo_encryptor</a>
 和 <a href="https://github.com/hotjuicew/hugoArticleEncryptor/blob/master/README-zh_CN.md" target="_blank" rel="noopener">hugoArticleEncryptor</a>
 都会对我的主题样式产生严重的影响，导致无法使用，如果有需要彻底加密的还是建议去参考他们的实现；</p>
<p>这里分享一下笔者基于 Li4n0 将加密过程改到 shortcode 中的代码如下，：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="c">&lt;!-- Other head elements --&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/crypto-js/3.1.9-1/crypto-js.js&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">{{ $_hugo_config := `{ &#34;version&#34;: 1 }` }}
</span></span><span class="line"><span class="cl">{{/*
</span></span><span class="line"><span class="cl">    ## Hugo Encrypt
</span></span><span class="line"><span class="cl">    ### Params:
</span></span><span class="line"><span class="cl">    - `password`:
</span></span><span class="line"><span class="cl">        require param
</span></span><span class="line"><span class="cl">    - Simple
</span></span><span class="line"><span class="cl">*/}}
</span></span><span class="line"><span class="cl">{{/* DEFAULTS */}}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;hugo-encryptor-container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;hugo-encryptor-prompt&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    {{ if eq .Site.Params.hugoEncryptorLanguage &#34;en-us&#34; }}
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>Part of this article is encrypted with password:<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    {{ else }}
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>文章的部分内容被密码保护：<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    {{ end }}
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;hugo-encryptor-form&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">input</span>
</span></span><span class="line"><span class="cl">      <span class="na">class</span><span class="o">=</span><span class="s">&#34;hugo-encryptor-input&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">placeholder</span><span class="o">=</span><span class="s">&#39;{{ if eq .Site.Params.hugoEncryptorLanguage &#34;en-us&#34; }}Please input the password{{ else }}请输入密码{{ end }}&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">input</span>
</span></span><span class="line"><span class="cl">      <span class="na">class</span><span class="o">=</span><span class="s">&#34;hugo-encryptor-button&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">type</span><span class="o">=</span><span class="s">&#34;button&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">value</span><span class="o">=</span><span class="s">&#39;{{ if eq .Site.Params.hugoEncryptorLanguage &#34;en-us&#34; }}Click to verify{{ else }}CLICK{{ end }}&#39;</span>
</span></span><span class="line"><span class="cl">      <span class="na">onclick</span><span class="o">=</span><span class="s">&#34;_click_handler(this)&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span>
</span></span><span class="line"><span class="cl">    <span class="na">class</span><span class="o">=</span><span class="s">&#34;hugo-encryptor-cipher-text&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">data-password</span><span class="o">=</span><span class="s">&#34;{{ .Get 0 }}&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">style</span><span class="o">=</span><span class="s">&#34;display: none;&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">span</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;display: none;&#34;</span><span class="p">&gt;</span>--- DON&#39;T MODIFY THIS LINE ---<span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    {{ .Inner }}
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// This script should be included in your Hugo templates
</span></span></span><span class="line"><span class="cl"><span class="c1">// Make sure to include the crypto-js library in your HTML
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">sanitizeContent</span><span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// Remove unwanted characters (like control characters)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">return</span> <span class="nx">content</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/[\x00-\x1F\x7F]/g</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">).</span><span class="nx">trim</span><span class="p">();</span> <span class="c1">// Remove control characters and trim whitespace
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">encryptContent</span><span class="p">(</span><span class="nx">password</span><span class="p">,</span> <span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">key</span> <span class="o">=</span> <span class="nx">CryptoJS</span><span class="p">.</span><span class="nx">MD5</span><span class="p">(</span><span class="nx">password</span><span class="p">).</span><span class="nx">toString</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">iv</span> <span class="o">=</span> <span class="nx">key</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="mi">16</span><span class="p">);</span> <span class="c1">// Use the second half of the key as IV
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kr">const</span> <span class="nx">paddedContent</span> <span class="o">=</span> <span class="nx">padContent</span><span class="p">(</span><span class="nx">content</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">encrypted</span> <span class="o">=</span> <span class="nx">CryptoJS</span><span class="p">.</span><span class="nx">AES</span><span class="p">.</span><span class="nx">encrypt</span><span class="p">(</span><span class="nx">paddedContent</span><span class="p">,</span> <span class="nx">CryptoJS</span><span class="p">.</span><span class="nx">enc</span><span class="p">.</span><span class="nx">Utf8</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">key</span><span class="p">),</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">iv</span><span class="o">:</span> <span class="nx">CryptoJS</span><span class="p">.</span><span class="nx">enc</span><span class="p">.</span><span class="nx">Utf8</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">iv</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">        <span class="nx">mode</span><span class="o">:</span> <span class="nx">CryptoJS</span><span class="p">.</span><span class="nx">mode</span><span class="p">.</span><span class="nx">CBC</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">padding</span><span class="o">:</span> <span class="nx">CryptoJS</span><span class="p">.</span><span class="nx">pad</span><span class="p">.</span><span class="nx">Pkcs7</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">CryptoJS</span><span class="p">.</span><span class="nx">enc</span><span class="p">.</span><span class="nx">Base64</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">encrypted</span><span class="p">.</span><span class="nx">ciphertext</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">padContent</span><span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">blockSize</span> <span class="o">=</span> <span class="mi">32</span><span class="p">;</span> <span class="c1">// AES block size
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kr">const</span> <span class="nx">padlen</span> <span class="o">=</span> <span class="nx">blockSize</span> <span class="o">-</span> <span class="p">(</span><span class="nx">content</span><span class="p">.</span><span class="nx">length</span> <span class="o">%</span> <span class="nx">blockSize</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// const padding = String.fromCharCode(padlen).repeat(padlen);
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">// return content + padding;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">return</span> <span class="nx">content</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">processEncryptedBlocks</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">blocks</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelectorAll</span><span class="p">(</span><span class="s1">&#39;.hugo-encryptor-cipher-text&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">blocks</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">block</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">password</span> <span class="o">=</span> <span class="nx">block</span><span class="p">.</span><span class="nx">getAttribute</span><span class="p">(</span><span class="s1">&#39;data-password&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">content</span> <span class="o">=</span> <span class="nx">block</span><span class="p">.</span><span class="nx">innerHTML</span><span class="p">.</span><span class="nx">trim</span><span class="p">();</span> <span class="c1">// Trim whitespace
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="kr">const</span> <span class="nx">sanitizedContent</span> <span class="o">=</span> <span class="nx">sanitizeContent</span><span class="p">(</span><span class="nx">content</span><span class="p">);</span> <span class="c1">// Sanitize content
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="kr">const</span> <span class="nx">encryptedContent</span> <span class="o">=</span> <span class="nx">encryptContent</span><span class="p">(</span><span class="nx">password</span><span class="p">,</span> <span class="nx">sanitizedContent</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nx">block</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="nx">encryptedContent</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nx">block</span><span class="p">.</span><span class="nx">removeAttribute</span><span class="p">(</span><span class="s1">&#39;data-password&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Append the decrypt.js script
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kr">const</span> <span class="nx">script</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s1">&#39;script&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">script</span><span class="p">.</span><span class="nx">src</span> <span class="o">=</span> <span class="s1">&#39;/js/decrypt.js&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">script</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Call the function to process the blocks after the DOM is fully loaded
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nb">document</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;DOMContentLoaded&#39;</span><span class="p">,</span> <span class="nx">processEncryptedBlocks</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>对应的样式设置如下</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="c">/* change the style of the encrypt button &amp; input */</span>
</span></span><span class="line"><span class="cl"><span class="c">/* only encrypt once in one posts. */</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">hugo-encryptor-container</span><span class="p">:</span><span class="nd">has</span><span class="o">(&gt;</span><span class="p">.</span><span class="nc">hugo-encryptor-prompt</span><span class="o">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">border-top</span><span class="p">:</span> <span class="mi">2</span><span class="kt">px</span> <span class="kc">solid</span> <span class="kc">black</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">border-bottom</span><span class="p">:</span> <span class="mi">2</span><span class="kt">px</span> <span class="kc">solid</span> <span class="kc">black</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="c">/* background: rgb(0 0 0 / 20%); */</span>
</span></span><span class="line"><span class="cl">    <span class="n">backdrop-filter</span><span class="p">:</span> <span class="nb">blur</span><span class="p">(</span><span class="mi">5</span><span class="kt">px</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">padding</span><span class="p">:</span> <span class="mi">5</span><span class="kt">px</span><span class="p">;</span>   
</span></span><span class="line"><span class="cl">    <span class="k">margin-bottom</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">hugo-encryptor-container</span><span class="p">:</span><span class="nd">has</span><span class="o">(&gt;</span><span class="p">.</span><span class="nc">hugo-encryptor-prompt</span><span class="o">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">border-top</span><span class="p">:</span> <span class="mi">2</span><span class="kt">px</span> <span class="kc">solid</span> <span class="mh">#5cbd63</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">border-bottom</span><span class="p">:</span> <span class="mi">2</span><span class="kt">px</span> <span class="kc">solid</span> <span class="mh">#5cbd63</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">hugo-encryptor-prompt</span> <span class="p">{</span><span class="k">font-weight</span><span class="p">:</span> <span class="kc">bold</span><span class="p">;}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">input</span><span class="p">.</span><span class="nc">hugo-encryptor-input</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">border</span><span class="p">:</span> <span class="mi">2</span><span class="kt">px</span> <span class="kc">solid</span> <span class="kc">black</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">primary</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">input</span><span class="p">.</span><span class="nc">hugo-encryptor-button</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">border</span><span class="p">:</span> <span class="kc">unset</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">background</span><span class="p">:</span> <span class="kc">black</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">border-radius</span><span class="p">:</span> <span class="mi">20</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">padding</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span> <span class="mi">5</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">box-shadow</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span> <span class="mi">0</span><span class="kt">px</span> <span class="mi">2</span><span class="kt">px</span> <span class="mi">2</span><span class="kt">px</span> <span class="nb">rgb</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">color</span><span class="p">:</span><span class="kc">azure</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">input</span><span class="p">.</span><span class="nc">hugo-encryptor-button</span><span class="p">:</span><span class="nd">hover</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">background-color</span><span class="p">:</span><span class="mh">#5cbd63</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">transition</span><span class="p">:</span> <span class="mf">0.7</span><span class="kt">s</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">input</span><span class="p">.</span><span class="nc">hugo-encryptor-button</span><span class="p">:</span><span class="nd">focus</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">outline-color</span><span class="p">:</span> <span class="kc">transparent</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">outline-style</span><span class="p">:</span><span class="kc">solid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">box-shadow</span><span class="p">:</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">4</span><span class="kt">px</span> <span class="mh">#5cbd63</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">input</span><span class="p">.</span><span class="nc">hugo-encryptor-input</span><span class="p">:</span><span class="nd">focus</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">outline-color</span><span class="p">:</span> <span class="kc">transparent</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">outline-style</span><span class="p">:</span><span class="kc">solid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">box-shadow</span><span class="p">:</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">1</span><span class="kt">px</span> <span class="mh">#0e0912</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="nt">input</span><span class="p">.</span><span class="nc">hugo-encryptor-input</span><span class="p">:</span><span class="nd">focus</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">box-shadow</span><span class="p">:</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">1</span><span class="kt">px</span> <span class="mh">#5cbd63</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-single</span><span class="p">:</span><span class="nd">has</span><span class="o">(</span><span class="p">.</span><span class="nc">post-content</span> <span class="p">.</span><span class="nc">hugo-encryptor-prompt</span><span class="o">)</span> <span class="p">#</span><span class="nn">toc-container</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">display</span><span class="p">:</span> <span class="kc">none</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>此外当你有加密的需求，记得把你的 repo 改为 Private，不然图啥呢是吧🔒；</p>
<h2 id="fi">FI</h2>
<blockquote>
<p>我可以不用，但是我得有啊，你说是不?</p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>修改Hugo中Markdown的基础渲染</title>
      <link>https://aikenh.cn/posts/%E4%BF%AE%E6%94%B9hugo%E4%B8%ADmarkdown%E7%9A%84%E5%9F%BA%E7%A1%80%E6%B8%B2%E6%9F%93/</link>
      <pubDate>Tue, 17 Dec 2024 17:38:18 +0000</pubDate>
      <guid>https://aikenh.cn/posts/%E4%BF%AE%E6%94%B9hugo%E4%B8%ADmarkdown%E7%9A%84%E5%9F%BA%E7%A1%80%E6%B8%B2%E6%9F%93/</guid>
      <description>利用render hook修改markdown元素的默认渲染样式</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>利用 hugo 主题的 render hook 的功能，修改 markdown 转换为 html 的样式，通过这种方法更改特定 Markdown 元素的渲染；</p>

</blockquote>
<h2 id="whats-render-hook-in-hugo-啥是渲染钩子">What&rsquo;s Render Hook In Hugo 啥是渲染钩子</h2>
<p>Render Hook 是 Hugo 给希望增强 Markdown 渲染功能的开发者留出的工具，通过 Render Hook 可以使开发者为各种 Markdown 元素创建自定义的渲染模版，满足不同用户对于渲染的不同需求；</p>
<p>具体而言，当编辑/创建如下这些特定路径的文件，其会覆盖默认的 markdown 渲染成 html 的方式，具体路径为 <span class="sidenote-number"><small class="sidenote"><a href="https://gohugo.io/render-hooks/introduction/" target="_blank" rel="noopener">Render Hooks Introduction</a></small></span> ：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>text</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">layouts/
</span></span><span class="line"><span class="cl">└── _default/
</span></span><span class="line"><span class="cl">    └── _markup/
</span></span><span class="line"><span class="cl">        ├── render-blockquote.html  # 渲染引用快
</span></span><span class="line"><span class="cl">        ├── render-codeblock.html   # 渲染代码块
</span></span><span class="line"><span class="cl">        ├── render-image.html       # 图片
</span></span><span class="line"><span class="cl">        ├── render-link.html        # 链接
</span></span><span class="line"><span class="cl">        └── render-table.html       # 表格</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>具体的参数和各种类型的具体文件，请在修改的时候参考对应的官方文档即可，如：<a href="https://gohugo.io/render-hooks/code-blocks/" target="_blank" rel="noopener">codeBlock</a>
</p>
<h3 id="why-为啥使用它呢">Why ？为啥使用它呢</h3>
<p>简单介绍 Render Hook 后，其实其优点就呼之欲出了：</p>
<ul>
<li>灵活 | 可自定义 | 增强功能：可以根据自己的需求随意的更改渲染的样式，甚至嵌入 js 引入复杂功能（收起，复制等）；</li>
<li>无需对博文做任何调整，不破坏 markdown 本身的可迁移性；</li>
<li>一劳永逸，统一管理；</li>
</ul>
<p>同时默认的样式在功能和外观上都比较基础，很多特性不被支持，如：</p>
<ul>
<li>外部打开链接</li>
<li>代码块的复制和折叠</li>
<li>图片的大小限制和位置限制等</li>
</ul>
<p>而为了支持这些特性，相比借助简码使用支持原生 markdown 的 render hook 去实现新特性，保持文章的简洁和完整性，那当然是最好不过；</p>
<h2 id="define-personal-render-定义自己的渲染">Define Personal Render 定义自己的渲染</h2>
<h3 id="mermaid-流程图支持">Mermaid 流程图支持</h3>
<p><a href="https://gohugo.io/content-management/diagrams/" target="_blank" rel="noopener">官方文档</a>
已经给出了对应的支持方案，主要分为三步：</p>
<p>一、在 <code>layouts/_default/_markup/render-codeblock-mermaid.html</code> 中添加</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">pre</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;mermaid&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    {{- .Inner | htmlEscape | safeHTML }}
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">pre</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  {{ .Page.Store.Set &#34;hasMermaid&#34; true }}</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>二、在内容模版的底部添加如下内容（这里我是添加到 ``layouts/_default/single.html` 中）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">{{ if .Store.Get &#34;hasMermaid&#34; }}
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;module&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="kr">import</span> <span class="nx">mermaid</span> <span class="nx">from</span> <span class="s1">&#39;https://cdn.jsdmirror.com/npm/mermaid/dist/mermaid.esm.min.mjs&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// import mermaid from &#39;https://cdn.jsdelivr.net/npm/mermaid/+esm&#39;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">mermaid</span><span class="p">.</span><span class="nx">initialize</span><span class="p">({</span> 
</span></span><span class="line"><span class="cl">      <span class="nx">startOnLoad</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="s1">&#39;theme&#39;</span><span class="o">:</span> <span class="s1">&#39;dark&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">     <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  {{ end }} </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><blockquote>
<p>可以修改 CDN 来加速 mermaid 的加载 <span class="sidenote-number"><small class="sidenote">感谢blog.jsdmirror.com 的镜像站</small></span></p>
</blockquote>
<p>三、可以在 markdown 中通过代码块的方式调用 mermaid ：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217194932.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217194932.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217194932.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>四、如果 mermaid 仍然渲染失败，或者没有开始渲染，尝试将 guessSyntax 设置为 false 如下 <span class="sidenote-number"><small class="sidenote"><a href="https://github.com/adityatelange/hugo-PaperMod/discussions/850" target="_blank" rel="noopener">Mermaid doesn&rsquo;t work </a></small></span> <span class="sidenote-number"><small class="sidenote"><a href="https://ooe.ooo/posts/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E6%90%AD%E5%BB%BAhugo%E5%8D%9A%E5%AE%A2/" target="_blank" rel="noopener">从零开始搭建Hugo博客</a></small></span>：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">markup</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">highlight</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">guessSyntax</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>最终应该可正常渲染 mermaid，下面是一个随机例子</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217201621.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217201621.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217201621.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><a href="https://ooe.ooo/posts/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E6%90%AD%E5%BB%BAhugo%E5%8D%9A%E5%AE%A2/" target="_blank" rel="noopener">从零开始搭建Hugo博客</a>
 中还有两种其他的支持 mermaid 的方式，感兴趣的也可以参考；</p>
<h3 id="image-自适应图片大小--fancybox-查看原图">Image 自适应图片大小 &amp; FancyBox 查看原图</h3>
<p>多年图像不居中就难受症候群，对原始的图片渲染确实是十分不满意，同时一些比较大/长的图片也会很破坏整个页面的结构和阅读体验，为了避免用 html 逐个调整，因此修改图像的默认 render hook <span class="sidenote-number"><small class="sidenote">这里感谢<a href="https://lifeislife.cn/posts/hugo%E4%B8%BB%E9%A2%98%E9%85%8D%E7%BD%AE/" target="_blank" rel="noopener">夜云泊</a>
分享的十分完整的解决方案</small></span> ；</p>
<p>这里我针对 PaperMod 主题对<a href="https://lifeislife.cn/posts/hugo%E4%B8%BB%E9%A2%98%E9%85%8D%E7%BD%AE/" target="_blank" rel="noopener">夜云泊</a>
 提供的代码做了简单的改动，具体原因已不可考，依稀记得是由于原始的 markdown 中有部分用 html 呈现的图像会有一些问题：</p>
<p>修改后的 <code>render-image.html</code> 如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">{{- $u := urls.Parse .Destination -}}
</span></span><span class="line"><span class="cl">{{- $src := $u.String -}}
</span></span><span class="line"><span class="cl">{{- if not $u.IsAbs -}}
</span></span><span class="line"><span class="cl">  {{- $path := strings.TrimPrefix &#34;./&#34; $u.Path }}
</span></span><span class="line"><span class="cl">  {{- with or (.PageInner.Resources.Get $path) (resources.Get $path) -}}
</span></span><span class="line"><span class="cl">    {{- $src = .RelPermalink -}}
</span></span><span class="line"><span class="cl">    {{- with $u.RawQuery -}}
</span></span><span class="line"><span class="cl">      {{- $src = printf &#34;%s?%s&#34; $src . -}}
</span></span><span class="line"><span class="cl">    {{- end -}}
</span></span><span class="line"><span class="cl">    {{- with $u.Fragment -}}
</span></span><span class="line"><span class="cl">      {{- $src = printf &#34;%s#%s&#34; $src . -}}
</span></span><span class="line"><span class="cl">    {{- end -}}
</span></span><span class="line"><span class="cl">  {{- end -}}
</span></span><span class="line"><span class="cl">{{- end -}}
</span></span><span class="line"><span class="cl">{{- $attributes := merge .Attributes (dict &#34;alt&#34; .Text &#34;src&#34; $src &#34;title&#34; (.Title | transform.HTMLEscape) &#34;loading&#34; &#34;lazy&#34;) -}}
</span></span><span class="line"><span class="cl">{{if .Page.Site.Params.fancybox }}
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;post-img-view&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">a</span> <span class="na">data-fancybox</span><span class="o">=</span><span class="s">&#34;gallery&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;{{ .Destination | safeURL }}&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">img</span> <span class="err">{{</span><span class="na">-</span> <span class="na">with</span> <span class="err">$</span><span class="na">attributes</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl">    <span class="err">{{</span><span class="na">-</span> <span class="na">range</span> <span class="err">$</span><span class="na">k</span><span class="err">,</span> <span class="err">$</span><span class="na">v</span> <span class="na">:</span><span class="o">=</span> <span class="s">.</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl">      <span class="err">{{</span><span class="na">-</span> <span class="na">if</span> <span class="err">$</span><span class="na">v</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl">        <span class="err">{{</span><span class="na">-</span> <span class="na">printf</span> <span class="err">&#34;</span> <span class="err">%</span><span class="na">s</span><span class="o">=</span><span class="s">%q&#34;</span> <span class="err">$</span><span class="na">k</span> <span class="err">$</span><span class="na">v</span> <span class="err">|</span> <span class="na">safeHTMLAttr</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl">      <span class="err">{{</span><span class="na">-</span> <span class="na">end</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl">    <span class="err">{{</span><span class="na">-</span> <span class="na">end</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl">  <span class="err">{{</span><span class="na">-</span> <span class="na">end</span> <span class="na">-</span><span class="err">}}</span>  <span class="na">class</span><span class="o">=</span><span class="s">&#34;responsive-image&#34;</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;{{ .Destination | safeURL }}&#34;</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;display: block; margin: 0 auto;&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">alt</span><span class="o">=</span><span class="s">&#34;{{ .Text }}&#34;</span> <span class="err">{{</span> <span class="na">with</span> <span class="err">.</span><span class="na">Title</span><span class="err">}}</span> <span class="na">title</span><span class="o">=</span><span class="s">&#34;{{ . }}&#34;</span> <span class="err">{{</span> <span class="na">end</span> <span class="err">}}</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">{{else}}
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">img</span>
</span></span><span class="line"><span class="cl">  <span class="err">{{</span><span class="na">-</span> <span class="na">range</span> <span class="err">$</span><span class="na">k</span><span class="err">,</span> <span class="err">$</span><span class="na">v</span> <span class="na">:</span><span class="o">=</span> <span class="s">$attributes</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl">    <span class="err">{{</span><span class="na">-</span> <span class="na">if</span> <span class="err">$</span><span class="na">v</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl">      <span class="err">{{</span><span class="na">-</span> <span class="na">printf</span> <span class="err">&#34;</span> <span class="err">%</span><span class="na">s</span><span class="o">=</span><span class="s">%q&#34;</span> <span class="err">$</span><span class="na">k</span> <span class="err">$</span><span class="na">v</span> <span class="err">|</span> <span class="na">safeHTMLAttr</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl">    <span class="err">{{</span><span class="na">-</span> <span class="na">end</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl">  <span class="err">{{</span><span class="na">-</span> <span class="na">end</span> <span class="na">-</span><span class="err">}}</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;display: block; margin: 0 auto; &#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;responsive-image&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">{{- /**/ -}}
</span></span><span class="line"><span class="cl">{{ end }}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nb">document</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;DOMContentLoaded&#34;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kd">var</span> <span class="nx">images</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelectorAll</span><span class="p">(</span><span class="s2">&#34;.responsive-image&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="kd">var</span> <span class="nx">maxHeight</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">innerHeight</span> <span class="o">/</span> <span class="mf">2.5</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="nx">images</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">image</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">image</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">maxHeight</span> <span class="o">=</span> <span class="nx">maxHeight</span> <span class="o">+</span> <span class="s2">&#34;px&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>然后去 Hugo 配置文件 <code>hugo.yml</code> 中新增一项：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">params</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">fancybox</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>具体的代码介绍请转向原作者 👍，最终效果如下：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217201918.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217201918.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217201918.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>开启 fancybox：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217201933.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217201933.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241217201933.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="link-默认新窗口打开网页">Link 默认新窗口打开网页</h3>
<p>参考： <a href="https://discourse.gohugo.io/t/how-to-open-plain-url-links-in-a-new-tab/25523/6" target="_blank" rel="noopener">How to open plain URL links in a new tab? - support - HUGO</a>
 实现如下 <code>render-link.html</code>：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;{{ .Destination | safeURL }}&#34;</span> <span class="err">{{</span> <span class="na">with</span> <span class="err">.</span><span class="na">Title</span><span class="err">}}</span> <span class="na">title</span><span class="o">=</span><span class="s">&#34;{{ . }}&#34;</span> <span class="err">{{</span> <span class="na">end</span> <span class="err">}}{{</span> <span class="na">if</span> <span class="na">strings</span><span class="err">.</span><span class="na">HasPrefix</span>
</span></span><span class="line"><span class="cl">    <span class="err">.</span><span class="na">Destination</span> <span class="err">&#34;</span><span class="na">http</span><span class="err">&#34;</span> <span class="err">}}</span> <span class="na">target</span><span class="o">=</span><span class="s">&#34;_blank&#34;</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;noopener&#34;</span> <span class="err">{{</span> <span class="na">end</span> <span class="err">}}</span><span class="p">&gt;</span>{{ .Text | safeHTML }}<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="code-block--代码折叠">Code Block  代码折叠</h3>
<p>由于有时会分享一些较长的代码，如果始终使代码完整呈现的话，其实页面不是那么的美观，而且也废滚轮，因此感觉折叠功能还是很必要的🔥，同时由于默认的样式怎么看都有些变扭，因此也顺便的加上标签栏来优化对应的样式。</p>
<p>实现代码折叠主要是如下思路：</p>
<ol>
<li>将原本的代码渲染包含在 <code>&lt;div class=&quot;code-content&quot;&gt;</code> 中；</li>
<li>新增同级别元素 <code>&lt;div class=&quot;code-title&quot;&gt;</code> 用于存放标题，同时作为开关控制折叠；</li>
</ol>
<p>接着话不多说开始实现，首先获取原本的基础实现和一些基本参数 <span class="sidenote-number"><small class="sidenote"><a href="https://gohugo.io/render-hooks/code-blocks/" target="_blank" rel="noopener">Code block render hooks | Hugo</a></small></span> 如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>go</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="p">{{</span> <span class="err">$</span><span class="nx">result</span> <span class="o">:=</span> <span class="nx">transform</span><span class="p">.</span><span class="nx">HighlightCodeBlock</span> <span class="p">.</span> <span class="p">}}</span>
</span></span><span class="line"><span class="cl"><span class="p">{{</span> <span class="err">$</span><span class="nx">result</span><span class="p">.</span><span class="nx">Wrapped</span> <span class="p">}}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><blockquote>
<p>该代码置于 <code>render-codeblock.html</code> 中，为默认的代码块渲染样式，如果需要修改特定语言的渲染，可以参考官方文档和 mermaid 的方式去处理；</p>
</blockquote>
<p>接着就很简单了，通过 <code>{{.Type}}</code> 可以获取语言类型信息用作 title，然后通过 js 和 css 实现折叠效果和样式调整即可，最终实现效果如下：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241218071014.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241218071014.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241218071014.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>折叠后：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241218071043.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241218071043.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241218071043.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>具体代码如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;code-block&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;code-title&#34;</span> <span class="na">onclick</span><span class="o">=</span><span class="s">&#34;toggleCode(this)&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;code-block-open&#34;</span><span class="p">&gt;&lt;</span><span class="nt">ion-icon</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;code-slash-outline&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">ion-icon</span><span class="p">&gt;&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">span</span><span class="p">&gt;</span>{{.Type}}<span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;code-content&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        {{ $result := transform.HighlightCodeBlock . }}
</span></span><span class="line"><span class="cl">        {{ $result.Wrapped }}
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">toggleCode</span><span class="p">(</span><span class="nx">element</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">codeContent</span> <span class="o">=</span> <span class="nx">element</span><span class="p">.</span><span class="nx">nextElementSibling</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">codeContent</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">display</span> <span class="o">===</span> <span class="s2">&#34;none&#34;</span> <span class="o">||</span> <span class="nx">codeContent</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">display</span> <span class="o">===</span> <span class="s2">&#34;&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">codeContent</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">display</span> <span class="o">=</span> <span class="s2">&#34;block&#34;</span><span class="p">;</span> <span class="c1">// Show the code block
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="nx">codeContent</span><span class="p">.</span><span class="nx">parentNode</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nx">remove</span><span class="p">(</span><span class="s2">&#34;code-has-hidden-child&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">codeContent</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">display</span> <span class="o">=</span> <span class="s2">&#34;none&#34;</span><span class="p">;</span> <span class="c1">// Hide the code block
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="nx">codeContent</span><span class="p">.</span><span class="nx">parentNode</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="s2">&#34;code-has-hidden-child&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">code-block</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">background</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">code</span><span class="o">-</span><span class="kc">block</span><span class="o">-</span><span class="n">bg</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">box-shadow</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span> <span class="mi">4</span><span class="kt">px</span> <span class="mi">30</span><span class="kt">px</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">border-radius</span><span class="p">:</span> <span class="mi">8</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">position</span><span class="p">:</span> <span class="kc">relative</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="c">/* padding: 2px; */</span>
</span></span><span class="line"><span class="cl">    <span class="k">margin</span><span class="p">:</span> <span class="mi">8</span><span class="kt">px</span> <span class="mi">0</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">code-title</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">display</span><span class="p">:</span> <span class="kc">flex</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">align-items</span><span class="p">:</span> <span class="kc">center</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">justify-content</span><span class="p">:</span> <span class="kc">space-between</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">margin</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">border-bottom</span><span class="p">:</span> <span class="mi">1</span><span class="kt">px</span> <span class="kc">solid</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">255</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mf">0.602</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">cursor</span><span class="p">:</span> <span class="kc">pointer</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">code-title</span> <span class="nt">span</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">letter-spacing</span><span class="p">:</span> <span class="mf">1.57</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">color</span><span class="p">:</span> <span class="nb">rgb</span><span class="p">(</span><span class="mi">212</span> <span class="mi">212</span> <span class="mi">212</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="c">/* width: 90%; */</span>
</span></span><span class="line"><span class="cl">    <span class="c">/* align-items: center; */</span>
</span></span><span class="line"><span class="cl">    <span class="k">font-size</span><span class="p">:</span> <span class="mi">1</span><span class="kt">rem</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">padding</span><span class="p">:</span> <span class="mi">5</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">padding-left</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">text-transform</span><span class="p">:</span> <span class="kc">capitalize</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">code-has-hidden-child</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">border</span><span class="p">:</span> <span class="mi">1</span><span class="kt">px</span> <span class="kc">solid</span> <span class="kc">salmon</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>此外这里也将 copy-code 按钮挪到了标题栏上，主要是修改 copy 的样式和渲染位置 <span class="sidenote-number"><small class="sidenote">可以参考 <a href="https://github.com/AikenH/papermod-sidebar/commit/2305a1c5a7098edaee8c850bae4efa2e22bb700d" target="_blank" rel="noopener">[Feat] update default code style · AikenH </a>
 剩余部分的修改，感兴趣的也可以点个 star，感谢。</small></span></p>
<h3 id="alert-blockquote-特殊引用块">Alert-Blockquote 特殊引用块</h3>
<p>在之前简码部分的博客已经介绍了一些特殊的引用块样式和实现，可以根据官网 <a href="https://gohugo.io/render-hooks/blockquotes/" target="_blank" rel="noopener">Blockquote render hooks | Hugo</a>
 将其改为自己的默认引用块即可，即可 markdown 中按照如下方式引用实现：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>markdown</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl"><span class="k">&gt; </span><span class="ge">[!{alert-keywork}]
</span></span></span><span class="line"><span class="cl"><span class="ge"></span>&gt; {alert-content}</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这是本博客中部分样式展示：</p>
<p>Note 样式：</p>



  
  

<blockquote class="alert-blockquote alert-note">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Note</span>
  </p>
  <p>test note block&rsquo;s style.</p>

</blockquote>
<p>important 样式</p>



  
  

<blockquote class="alert-blockquote alert-important">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0 1 14.25 13H8.06l-2.573 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25Zm7 2.25v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 9a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path>
    </svg>
    <span>Important</span>
  </p>
  <p>重要内容</p>

</blockquote>
<p>Error 样式</p>



  
  

<blockquote class="alert-blockquote alert-error">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Error</span>
  </p>
  <p>Error</p>

</blockquote>
<p>该部分可以发现大家都参考了 <a href="https://github.com/martignoni/hugo-notice" target="_blank" rel="noopener">hugo-notice</a>
 ，而本博客则是在其他博主分享 <span class="sidenote-number"><small class="sidenote">感谢 <a href="https://blog.grew.cc/posts/hugo-alert-blockquote/" target="_blank" rel="noopener">tom&rsquo;s blog</a></small></span> <span class="sidenote-number"><small class="sidenote">感谢<a href="https://blog.hentioe.dev/posts/hugo-support-blockquote-alerts.html" target="_blank" rel="noopener">绅士喵</a></small></span> 的样式之上根据本人的 Obsidian 调整了一下样式和默认值，具体实现如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">{{ $alertTypes := dict
</span></span><span class="line"><span class="cl">  &#34;note&#34; &#34;<span class="p">&lt;</span><span class="nt">path</span> <span class="na">d</span><span class="o">=</span><span class="s">\&#34;M0</span> <span class="na">8a8</span> <span class="na">8</span> <span class="na">0</span> <span class="na">1</span> <span class="na">1</span> <span class="na">16</span> <span class="na">0A8</span> <span class="na">8</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">0</span> <span class="na">8Zm8-6</span><span class="err">.</span><span class="na">5a6</span><span class="err">.</span><span class="na">5</span> <span class="na">6</span><span class="err">.</span><span class="na">5</span> <span class="na">0</span> <span class="na">1</span> <span class="na">0</span> <span class="na">0</span> <span class="na">13</span> <span class="na">6</span><span class="err">.</span><span class="na">5</span> <span class="na">6</span><span class="err">.</span><span class="na">5</span> <span class="na">0</span> <span class="na">0</span> <span class="na">0</span> <span class="na">0-13ZM6</span><span class="err">.</span><span class="na">5</span> <span class="na">7</span><span class="err">.</span><span class="na">75A</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">7</span><span class="err">.</span><span class="na">25</span> <span class="na">7h1a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75v2</span><span class="err">.</span><span class="na">75h</span><span class="err">.</span><span class="na">25a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">0</span> <span class="na">1</span><span class="err">.</span><span class="na">5h-2a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">0-1</span><span class="err">.</span><span class="na">5h</span><span class="err">.</span><span class="na">25v-2h-</span><span class="err">.</span><span class="na">25a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1-</span><span class="err">.</span><span class="na">75-</span><span class="err">.</span><span class="na">75ZM8</span> <span class="na">6a1</span> <span class="na">1</span> <span class="na">0</span> <span class="na">1</span> <span class="na">1</span> <span class="na">0-2</span> <span class="na">1</span> <span class="na">1</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">0</span> <span class="na">2Z</span><span class="err">\&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">path</span><span class="p">&gt;</span>&#34;
</span></span><span class="line"><span class="cl">  &#34;tip&#34; &#34;<span class="p">&lt;</span><span class="nt">path</span> <span class="na">d</span><span class="o">=</span><span class="s">\&#34;M8</span> <span class="na">1</span><span class="err">.</span><span class="na">5c-2</span><span class="err">.</span><span class="na">363</span> <span class="na">0-4</span> <span class="na">1</span><span class="err">.</span><span class="na">69-4</span> <span class="na">3</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="err">.</span><span class="na">984</span><span class="err">.</span><span class="na">424</span> <span class="na">1</span><span class="err">.</span><span class="na">625</span><span class="err">.</span><span class="na">984</span> <span class="na">2</span><span class="err">.</span><span class="na">304l</span><span class="err">.</span><span class="na">214</span><span class="err">.</span><span class="na">253c</span><span class="err">.</span><span class="na">223</span><span class="err">.</span><span class="na">264</span><span class="err">.</span><span class="na">47</span><span class="err">.</span><span class="na">556</span><span class="err">.</span><span class="na">673</span><span class="err">.</span><span class="na">848</span><span class="err">.</span><span class="na">284</span><span class="err">.</span><span class="na">411</span><span class="err">.</span><span class="na">537</span><span class="err">.</span><span class="na">896</span><span class="err">.</span><span class="na">621</span> <span class="na">1</span><span class="err">.</span><span class="na">49a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1-1</span><span class="err">.</span><span class="na">484</span><span class="err">.</span><span class="na">211c-</span><span class="err">.</span><span class="na">04-</span><span class="err">.</span><span class="na">282-</span><span class="err">.</span><span class="na">163-</span><span class="err">.</span><span class="na">547-</span><span class="err">.</span><span class="na">37-</span><span class="err">.</span><span class="na">847a8</span><span class="err">.</span><span class="na">456</span> <span class="na">8</span><span class="err">.</span><span class="na">456</span> <span class="na">0</span> <span class="na">0</span> <span class="na">0-</span><span class="err">.</span><span class="na">542-</span><span class="err">.</span><span class="na">68c-</span><span class="err">.</span><span class="na">084-</span><span class="err">.</span><span class="na">1-</span><span class="err">.</span><span class="na">173-</span><span class="err">.</span><span class="na">205-</span><span class="err">.</span><span class="na">268-</span><span class="err">.</span><span class="na">32C3</span><span class="err">.</span><span class="na">201</span> <span class="na">7</span><span class="err">.</span><span class="na">75</span> <span class="na">2</span><span class="err">.</span><span class="na">5</span> <span class="na">6</span><span class="err">.</span><span class="na">766</span> <span class="na">2</span><span class="err">.</span><span class="na">5</span> <span class="na">5</span><span class="err">.</span><span class="na">25</span> <span class="na">2</span><span class="err">.</span><span class="na">5</span> <span class="na">2</span><span class="err">.</span><span class="na">31</span> <span class="na">4</span><span class="err">.</span><span class="na">863</span> <span class="na">0</span> <span class="na">8</span> <span class="na">0s5</span><span class="err">.</span><span class="na">5</span> <span class="na">2</span><span class="err">.</span><span class="na">31</span> <span class="na">5</span><span class="err">.</span><span class="na">5</span> <span class="na">5</span><span class="err">.</span><span class="na">25c0</span> <span class="na">1</span><span class="err">.</span><span class="na">516-</span><span class="err">.</span><span class="na">701</span> <span class="na">2</span><span class="err">.</span><span class="na">5-1</span><span class="err">.</span><span class="na">328</span> <span class="na">3</span><span class="err">.</span><span class="na">259-</span><span class="err">.</span><span class="na">095</span><span class="err">.</span><span class="na">115-</span><span class="err">.</span><span class="na">184</span><span class="err">.</span><span class="na">22-</span><span class="err">.</span><span class="na">268</span><span class="err">.</span><span class="na">319-</span><span class="err">.</span><span class="na">207</span><span class="err">.</span><span class="na">245-</span><span class="err">.</span><span class="na">383</span><span class="err">.</span><span class="na">453-</span><span class="err">.</span><span class="na">541</span><span class="err">.</span><span class="na">681-</span><span class="err">.</span><span class="na">208</span><span class="err">.</span><span class="na">3-</span><span class="err">.</span><span class="na">33</span><span class="err">.</span><span class="na">565-</span><span class="err">.</span><span class="na">37</span><span class="err">.</span><span class="na">847a</span><span class="err">.</span><span class="na">751</span><span class="err">.</span><span class="na">751</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1-1</span><span class="err">.</span><span class="na">485-</span><span class="err">.</span><span class="na">212c</span><span class="err">.</span><span class="na">084-</span><span class="err">.</span><span class="na">593</span><span class="err">.</span><span class="na">337-1</span><span class="err">.</span><span class="na">078</span><span class="err">.</span><span class="na">621-1</span><span class="err">.</span><span class="na">489</span><span class="err">.</span><span class="na">203-</span><span class="err">.</span><span class="na">292</span><span class="err">.</span><span class="na">45-</span><span class="err">.</span><span class="na">584</span><span class="err">.</span><span class="na">673-</span><span class="err">.</span><span class="na">848</span><span class="err">.</span><span class="na">075-</span><span class="err">.</span><span class="na">088</span><span class="err">.</span><span class="na">147-</span><span class="err">.</span><span class="na">173</span><span class="err">.</span><span class="na">213-</span><span class="err">.</span><span class="na">253</span><span class="err">.</span><span class="na">561-</span><span class="err">.</span><span class="na">679</span><span class="err">.</span><span class="na">985-1</span><span class="err">.</span><span class="na">32</span><span class="err">.</span><span class="na">985-2</span><span class="err">.</span><span class="na">304</span> <span class="na">0-2</span><span class="err">.</span><span class="na">06-1</span><span class="err">.</span><span class="na">637-3</span><span class="err">.</span><span class="na">75-4-3</span><span class="err">.</span><span class="na">75ZM5</span><span class="err">.</span><span class="na">75</span> <span class="na">12h4</span><span class="err">.</span><span class="na">5a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">0</span> <span class="na">1</span><span class="err">.</span><span class="na">5h-4</span><span class="err">.</span><span class="na">5a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">0-1</span><span class="err">.</span><span class="na">5ZM6</span> <span class="na">15</span><span class="err">.</span><span class="na">25a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="err">.</span><span class="na">75-</span><span class="err">.</span><span class="na">75h2</span><span class="err">.</span><span class="na">5a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">0</span> <span class="na">1</span><span class="err">.</span><span class="na">5h-2</span><span class="err">.</span><span class="na">5a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1-</span><span class="err">.</span><span class="na">75-</span><span class="err">.</span><span class="na">75Z</span><span class="err">\&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">path</span><span class="p">&gt;</span>&#34;
</span></span><span class="line"><span class="cl">  &#34;important&#34; &#34;<span class="p">&lt;</span><span class="nt">path</span> <span class="na">d</span><span class="o">=</span><span class="s">\&#34;M0</span> <span class="na">1</span><span class="err">.</span><span class="na">75C0</span> <span class="err">.</span><span class="na">784</span><span class="err">.</span><span class="na">784</span> <span class="na">0</span> <span class="na">1</span><span class="err">.</span><span class="na">75</span> <span class="na">0h12</span><span class="err">.</span><span class="na">5C15</span><span class="err">.</span><span class="na">216</span> <span class="na">0</span> <span class="na">16</span> <span class="err">.</span><span class="na">784</span> <span class="na">16</span> <span class="na">1</span><span class="err">.</span><span class="na">75v9</span><span class="err">.</span><span class="na">5A1</span><span class="err">.</span><span class="na">75</span> <span class="na">1</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">14</span><span class="err">.</span><span class="na">25</span> <span class="na">13H8</span><span class="err">.</span><span class="na">06l-2</span><span class="err">.</span><span class="na">573</span> <span class="na">2</span><span class="err">.</span><span class="na">573A1</span><span class="err">.</span><span class="na">458</span> <span class="na">1</span><span class="err">.</span><span class="na">458</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">3</span> <span class="na">14</span><span class="err">.</span><span class="na">543V13H1</span><span class="err">.</span><span class="na">75A1</span><span class="err">.</span><span class="na">75</span> <span class="na">1</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">0</span> <span class="na">11</span><span class="err">.</span><span class="na">25Zm1</span><span class="err">.</span><span class="na">75-</span><span class="err">.</span><span class="na">25a</span><span class="err">.</span><span class="na">25</span><span class="err">.</span><span class="na">25</span> <span class="na">0</span> <span class="na">0</span> <span class="na">0-</span><span class="err">.</span><span class="na">25</span><span class="err">.</span><span class="na">25v9</span><span class="err">.</span><span class="na">5c0</span> <span class="err">.</span><span class="na">138</span><span class="err">.</span><span class="na">112</span><span class="err">.</span><span class="na">25</span><span class="err">.</span><span class="na">25</span><span class="err">.</span><span class="na">25h2a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75v2</span><span class="err">.</span><span class="na">19l2</span><span class="err">.</span><span class="na">72-2</span><span class="err">.</span><span class="na">72a</span><span class="err">.</span><span class="na">749</span><span class="err">.</span><span class="na">749</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="err">.</span><span class="na">53-</span><span class="err">.</span><span class="na">22h6</span><span class="err">.</span><span class="na">5a</span><span class="err">.</span><span class="na">25</span><span class="err">.</span><span class="na">25</span> <span class="na">0</span> <span class="na">0</span> <span class="na">0</span> <span class="err">.</span><span class="na">25-</span><span class="err">.</span><span class="na">25v-9</span><span class="err">.</span><span class="na">5a</span><span class="err">.</span><span class="na">25</span><span class="err">.</span><span class="na">25</span> <span class="na">0</span> <span class="na">0</span> <span class="na">0-</span><span class="err">.</span><span class="na">25-</span><span class="err">.</span><span class="na">25Zm7</span> <span class="na">2</span><span class="err">.</span><span class="na">25v2</span><span class="err">.</span><span class="na">5a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1-1</span><span class="err">.</span><span class="na">5</span> <span class="na">0v-2</span><span class="err">.</span><span class="na">5a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">1</span><span class="err">.</span><span class="na">5</span> <span class="na">0ZM9</span> <span class="na">9a1</span> <span class="na">1</span> <span class="na">0</span> <span class="na">1</span> <span class="na">1-2</span> <span class="na">0</span> <span class="na">1</span> <span class="na">1</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">2</span> <span class="na">0Z</span><span class="err">\&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">path</span><span class="p">&gt;</span>&#34;
</span></span><span class="line"><span class="cl">  &#34;warning&#34; &#34;<span class="p">&lt;</span><span class="nt">path</span> <span class="na">d</span><span class="o">=</span><span class="s">\&#34;M6.457</span> <span class="na">1</span><span class="err">.</span><span class="na">047c</span><span class="err">.</span><span class="na">659-1</span><span class="err">.</span><span class="na">234</span> <span class="na">2</span><span class="err">.</span><span class="na">427-1</span><span class="err">.</span><span class="na">234</span> <span class="na">3</span><span class="err">.</span><span class="na">086</span> <span class="na">0l6</span><span class="err">.</span><span class="na">082</span> <span class="na">11</span><span class="err">.</span><span class="na">378A1</span><span class="err">.</span><span class="na">75</span> <span class="na">1</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">14</span><span class="err">.</span><span class="na">082</span> <span class="na">15H1</span><span class="err">.</span><span class="na">918a1</span><span class="err">.</span><span class="na">75</span> <span class="na">1</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1-1</span><span class="err">.</span><span class="na">543-2</span><span class="err">.</span><span class="na">575Zm1</span><span class="err">.</span><span class="na">763</span><span class="err">.</span><span class="na">707a</span><span class="err">.</span><span class="na">25</span><span class="err">.</span><span class="na">25</span> <span class="na">0</span> <span class="na">0</span> <span class="na">0-</span><span class="err">.</span><span class="na">44</span> <span class="na">0L1</span><span class="err">.</span><span class="na">698</span> <span class="na">13</span><span class="err">.</span><span class="na">132a</span><span class="err">.</span><span class="na">25</span><span class="err">.</span><span class="na">25</span> <span class="na">0</span> <span class="na">0</span> <span class="na">0</span> <span class="err">.</span><span class="na">22</span><span class="err">.</span><span class="na">368h12</span><span class="err">.</span><span class="na">164a</span><span class="err">.</span><span class="na">25</span><span class="err">.</span><span class="na">25</span> <span class="na">0</span> <span class="na">0</span> <span class="na">0</span> <span class="err">.</span><span class="na">22-</span><span class="err">.</span><span class="na">368Zm</span><span class="err">.</span><span class="na">53</span> <span class="na">3</span><span class="err">.</span><span class="na">996v2</span><span class="err">.</span><span class="na">5a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1-1</span><span class="err">.</span><span class="na">5</span> <span class="na">0v-2</span><span class="err">.</span><span class="na">5a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">1</span><span class="err">.</span><span class="na">5</span> <span class="na">0ZM9</span> <span class="na">11a1</span> <span class="na">1</span> <span class="na">0</span> <span class="na">1</span> <span class="na">1-2</span> <span class="na">0</span> <span class="na">1</span> <span class="na">1</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">2</span> <span class="na">0Z</span><span class="err">\&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">path</span><span class="p">&gt;</span>&#34;
</span></span><span class="line"><span class="cl">  &#34;caution&#34; &#34;<span class="p">&lt;</span><span class="nt">path</span> <span class="na">d</span><span class="o">=</span><span class="s">\&#34;M4.47.22A.749.749</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">5</span> <span class="na">0h6c</span><span class="err">.</span><span class="na">199</span> <span class="na">0</span> <span class="err">.</span><span class="na">389</span><span class="err">.</span><span class="na">079</span><span class="err">.</span><span class="na">53</span><span class="err">.</span><span class="na">22l4</span><span class="err">.</span><span class="na">25</span> <span class="na">4</span><span class="err">.</span><span class="na">25c</span><span class="err">.</span><span class="na">141</span><span class="err">.</span><span class="na">14</span><span class="err">.</span><span class="na">22</span><span class="err">.</span><span class="na">331</span><span class="err">.</span><span class="na">22</span><span class="err">.</span><span class="na">53v6a</span><span class="err">.</span><span class="na">749</span><span class="err">.</span><span class="na">749</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1-</span><span class="err">.</span><span class="na">22</span><span class="err">.</span><span class="na">53l-4</span><span class="err">.</span><span class="na">25</span> <span class="na">4</span><span class="err">.</span><span class="na">25A</span><span class="err">.</span><span class="na">749</span><span class="err">.</span><span class="na">749</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">11</span> <span class="na">16H5a</span><span class="err">.</span><span class="na">749</span><span class="err">.</span><span class="na">749</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1-</span><span class="err">.</span><span class="na">53-</span><span class="err">.</span><span class="na">22L</span><span class="err">.</span><span class="na">22</span> <span class="na">11</span><span class="err">.</span><span class="na">53A</span><span class="err">.</span><span class="na">749</span><span class="err">.</span><span class="na">749</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">0</span> <span class="na">11V5c0-</span><span class="err">.</span><span class="na">199</span><span class="err">.</span><span class="na">079-</span><span class="err">.</span><span class="na">389</span><span class="err">.</span><span class="na">22-</span><span class="err">.</span><span class="na">53Zm</span><span class="err">.</span><span class="na">84</span> <span class="na">1</span><span class="err">.</span><span class="na">28L1</span><span class="err">.</span><span class="na">5</span> <span class="na">5</span><span class="err">.</span><span class="na">31v5</span><span class="err">.</span><span class="na">38l3</span><span class="err">.</span><span class="na">81</span> <span class="na">3</span><span class="err">.</span><span class="na">81h5</span><span class="err">.</span><span class="na">38l3</span><span class="err">.</span><span class="na">81-3</span><span class="err">.</span><span class="na">81V5</span><span class="err">.</span><span class="na">31L10</span><span class="err">.</span><span class="na">69</span> <span class="na">1</span><span class="err">.</span><span class="na">5ZM8</span> <span class="na">4a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75v3</span><span class="err">.</span><span class="na">5a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1-1</span><span class="err">.</span><span class="na">5</span> <span class="na">0v-3</span><span class="err">.</span><span class="na">5A</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">8</span> <span class="na">4Zm0</span> <span class="na">8a1</span> <span class="na">1</span> <span class="na">0</span> <span class="na">1</span> <span class="na">1</span> <span class="na">0-2</span> <span class="na">1</span> <span class="na">1</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">0</span> <span class="na">2Z</span><span class="err">\&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">path</span><span class="p">&gt;</span>&#34;
</span></span><span class="line"><span class="cl">  &#34;error&#34; &#34;<span class="p">&lt;</span><span class="nt">path</span> <span class="na">d</span><span class="o">=</span><span class="s">\&#34;M4.47.22A.749.749</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">5</span> <span class="na">0h6c</span><span class="err">.</span><span class="na">199</span> <span class="na">0</span> <span class="err">.</span><span class="na">389</span><span class="err">.</span><span class="na">079</span><span class="err">.</span><span class="na">53</span><span class="err">.</span><span class="na">22l4</span><span class="err">.</span><span class="na">25</span> <span class="na">4</span><span class="err">.</span><span class="na">25c</span><span class="err">.</span><span class="na">141</span><span class="err">.</span><span class="na">14</span><span class="err">.</span><span class="na">22</span><span class="err">.</span><span class="na">331</span><span class="err">.</span><span class="na">22</span><span class="err">.</span><span class="na">53v6a</span><span class="err">.</span><span class="na">749</span><span class="err">.</span><span class="na">749</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1-</span><span class="err">.</span><span class="na">22</span><span class="err">.</span><span class="na">53l-4</span><span class="err">.</span><span class="na">25</span> <span class="na">4</span><span class="err">.</span><span class="na">25A</span><span class="err">.</span><span class="na">749</span><span class="err">.</span><span class="na">749</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">11</span> <span class="na">16H5a</span><span class="err">.</span><span class="na">749</span><span class="err">.</span><span class="na">749</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1-</span><span class="err">.</span><span class="na">53-</span><span class="err">.</span><span class="na">22L</span><span class="err">.</span><span class="na">22</span> <span class="na">11</span><span class="err">.</span><span class="na">53A</span><span class="err">.</span><span class="na">749</span><span class="err">.</span><span class="na">749</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">0</span> <span class="na">11V5c0-</span><span class="err">.</span><span class="na">199</span><span class="err">.</span><span class="na">079-</span><span class="err">.</span><span class="na">389</span><span class="err">.</span><span class="na">22-</span><span class="err">.</span><span class="na">53Zm</span><span class="err">.</span><span class="na">84</span> <span class="na">1</span><span class="err">.</span><span class="na">28L1</span><span class="err">.</span><span class="na">5</span> <span class="na">5</span><span class="err">.</span><span class="na">31v5</span><span class="err">.</span><span class="na">38l3</span><span class="err">.</span><span class="na">81</span> <span class="na">3</span><span class="err">.</span><span class="na">81h5</span><span class="err">.</span><span class="na">38l3</span><span class="err">.</span><span class="na">81-3</span><span class="err">.</span><span class="na">81V5</span><span class="err">.</span><span class="na">31L10</span><span class="err">.</span><span class="na">69</span> <span class="na">1</span><span class="err">.</span><span class="na">5ZM8</span> <span class="na">4a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75v3</span><span class="err">.</span><span class="na">5a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1-1</span><span class="err">.</span><span class="na">5</span> <span class="na">0v-3</span><span class="err">.</span><span class="na">5A</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">8</span> <span class="na">4Zm0</span> <span class="na">8a1</span> <span class="na">1</span> <span class="na">0</span> <span class="na">1</span> <span class="na">1</span> <span class="na">0-2</span> <span class="na">1</span> <span class="na">1</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">0</span> <span class="na">2Z</span><span class="err">\&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">path</span><span class="p">&gt;</span>&#34;
</span></span><span class="line"><span class="cl">}}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">{{
</span></span><span class="line"><span class="cl">  $default := &#34;<span class="p">&lt;</span><span class="nt">path</span> <span class="na">d</span><span class="o">=</span><span class="s">\&#34;M0</span> <span class="na">8a8</span> <span class="na">8</span> <span class="na">0</span> <span class="na">1</span> <span class="na">1</span> <span class="na">16</span> <span class="na">0A8</span> <span class="na">8</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">0</span> <span class="na">8Zm8-6</span><span class="err">.</span><span class="na">5a6</span><span class="err">.</span><span class="na">5</span> <span class="na">6</span><span class="err">.</span><span class="na">5</span> <span class="na">0</span> <span class="na">1</span> <span class="na">0</span> <span class="na">0</span> <span class="na">13</span> <span class="na">6</span><span class="err">.</span><span class="na">5</span> <span class="na">6</span><span class="err">.</span><span class="na">5</span> <span class="na">0</span> <span class="na">0</span> <span class="na">0</span> <span class="na">0-13ZM6</span><span class="err">.</span><span class="na">5</span> <span class="na">7</span><span class="err">.</span><span class="na">75A</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">7</span><span class="err">.</span><span class="na">25</span> <span class="na">7h1a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75v2</span><span class="err">.</span><span class="na">75h</span><span class="err">.</span><span class="na">25a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">0</span> <span class="na">1</span><span class="err">.</span><span class="na">5h-2a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">0-1</span><span class="err">.</span><span class="na">5h</span><span class="err">.</span><span class="na">25v-2h-</span><span class="err">.</span><span class="na">25a</span><span class="err">.</span><span class="na">75</span><span class="err">.</span><span class="na">75</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1-</span><span class="err">.</span><span class="na">75-</span><span class="err">.</span><span class="na">75ZM8</span> <span class="na">6a1</span> <span class="na">1</span> <span class="na">0</span> <span class="na">1</span> <span class="na">1</span> <span class="na">0-2</span> <span class="na">1</span> <span class="na">1</span> <span class="na">0</span> <span class="na">0</span> <span class="na">1</span> <span class="na">0</span> <span class="na">2Z</span><span class="err">\&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">path</span><span class="p">&gt;</span>&#34;
</span></span><span class="line"><span class="cl">}}
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">{{ if eq .Type &#34;alert&#34; }}
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">blockquote</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;alert-blockquote alert-{{ .AlertType }}&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;alert-heading&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">svg</span> <span class="na">xmlns</span><span class="o">=</span><span class="s">&#34;http://www.w3.org/2000/svg&#34;</span> <span class="na">viewBox</span><span class="o">=</span><span class="s">&#34;0 0 16 16&#34;</span> <span class="na">width</span><span class="o">=</span><span class="s">&#34;16&#34;</span> <span class="na">height</span><span class="o">=</span><span class="s">&#34;16&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      {{- $alertType := index $alertTypes .AlertType | default $default }}
</span></span><span class="line"><span class="cl">      {{ $alertType | safeHTML }}
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">svg</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">span</span><span class="p">&gt;</span>{{ or (i18n .AlertType) (title .AlertType) }}<span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  {{ .Text | safeHTML }}
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">blockquote</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">{{ else }}
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">blockquote</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  {{ .Text | safeHTML }}
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">blockquote</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">{{ end }}</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">alert-blockquote</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--title-color</span><span class="p">:</span> <span class="mh">#fff</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--content-color</span><span class="p">:</span> <span class="kc">inherit</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">padding</span><span class="p">:</span> <span class="mi">18</span><span class="kt">px</span> <span class="mi">18</span><span class="kt">px</span> <span class="mi">10</span><span class="kt">px</span> <span class="mi">18</span><span class="kt">px</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">line-height</span><span class="p">:</span> <span class="mi">24</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">margin</span><span class="p">:</span> <span class="mi">1</span><span class="kt">rem</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">border-radius</span><span class="p">:</span> <span class="mi">4</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">content</span><span class="o">-</span><span class="kc">color</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* border-left: none !important; */</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* border: 1px solid black; */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">alert-blockquote</span> <span class="o">*,</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">alert-blockquote</span> <span class="o">*</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">content</span><span class="o">-</span><span class="kc">color</span><span class="p">)</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</span> <span class="nt">blockquote</span><span class="o">%</span><span class="nt">3Ep</span><span class="o">&gt;</span><span class="nt">p</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">padding</span><span class="p">:</span> <span class="kc">unset</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">alert-blockquote</span> <span class="p">.</span><span class="nc">alert-heading</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">margin</span><span class="p">:</span> <span class="mi">-18</span><span class="kt">px</span> <span class="mi">-18</span><span class="kt">px</span> <span class="mi">12</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">padding</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span> <span class="mi">18</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">border-radius</span><span class="p">:</span> <span class="mi">4</span><span class="kt">px</span> <span class="mi">4</span><span class="kt">px</span> <span class="mi">0</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-weight</span><span class="p">:</span> <span class="mi">600</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">title</span><span class="o">-</span><span class="kc">color</span><span class="p">)</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="kc">flex</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">align-items</span><span class="p">:</span> <span class="kc">center</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">alert-blockquote</span> <span class="p">.</span><span class="nc">alert-heading</span> <span class="nt">svg</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">width</span><span class="p">:</span> <span class="mi">1</span><span class="kt">em</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">height</span><span class="p">:</span> <span class="mi">1</span><span class="kt">em</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">margin-right</span><span class="p">:</span> <span class="mf">0.5</span><span class="kt">rem</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">fill</span><span class="p">:</span> <span class="kc">currentColor</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">alert-blockquote</span> <span class="nt">p</span><span class="p">:</span><span class="nd">last-child</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">margin-bottom</span><span class="p">:</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c">/* Light theme */</span>
</span></span><span class="line"><span class="cl"><span class="c">/* default */</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">alert-blockquote</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">border-top</span><span class="p">:</span><span class="kc">unset</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* border: 1px solid #166dd0; */</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* --title-background-color: rgba(221, 233, 244, 0.631); */</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--content-background-color</span><span class="p">:</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">221</span><span class="p">,</span> <span class="mi">233</span><span class="p">,</span> <span class="mi">244</span><span class="p">,</span> <span class="mf">0.602</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">alert-blockquote</span> <span class="o">&gt;</span> <span class="p">.</span><span class="nc">alert-heading</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* border-bottom: 1px dashed #166dd07c; */</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="mh">#0969da</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c">/* note */</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-note</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* border: 1px solid #166dd0; */</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* border-left-color: #0969da !important; */</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* --title-background-color: rgba(221, 233, 244, 0.631); */</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--content-background-color</span><span class="p">:</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">221</span><span class="p">,</span> <span class="mi">233</span><span class="p">,</span> <span class="mi">244</span><span class="p">,</span> <span class="mf">0.602</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-note</span> <span class="p">.</span><span class="nc">alert-heading</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="mh">#0969da</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c">/* tip */</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-tip</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* border: 1px solid #1a7f37; */</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* --title-background-color: rgb(173,193,182); */</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--content-background-color</span><span class="p">:</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">222</span><span class="p">,</span> <span class="mi">240</span><span class="p">,</span> <span class="mi">223</span><span class="p">,</span> <span class="mf">0.7</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-tip</span> <span class="p">.</span><span class="nc">alert-heading</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="mh">#1a7f37</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* border-bottom: 1px dashed #1a7f37; */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c">/* important */</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-important</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* border: 1px solid #8250df; */</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* border-left-color: #8250df !important; */</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* --title-background-color: #6843ae7c; */</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--content-background-color</span><span class="p">:</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">235</span><span class="p">,</span> <span class="mi">227</span><span class="p">,</span> <span class="mi">245</span><span class="p">,</span> <span class="mf">0.9</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-important</span> <span class="p">.</span><span class="nc">alert-heading</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="mh">#8250df</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* border-bottom: 1px dashed #8250df; */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c">/* warning */</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-warning</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* border: 1px solid #9a6700; */</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* border-left-color: #9a6700 !important; */</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* --title-background-color: rgb(232, 198, 140); */</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--content-background-color</span><span class="p">:</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">243</span><span class="p">,</span> <span class="mi">232</span><span class="p">,</span> <span class="mi">222</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-warning</span> <span class="p">.</span><span class="nc">alert-heading</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="mh">#9a6700</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* border-bottom: 1px dashed #9a6700; */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c">/* caution */</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-error</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-caution</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* border: 1px solid #cf222e; */</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* border-left-color: #cf222e !important; */</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* --title-background-color: rgb(244, 224, 223,0.5); */</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--content-background-color</span><span class="p">:</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">243</span><span class="p">,</span> <span class="mi">207</span><span class="p">,</span> <span class="mi">205</span><span class="p">,</span> <span class="mf">0.9</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-error</span> <span class="p">.</span><span class="nc">alert-heading</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-caution</span> <span class="p">.</span><span class="nc">alert-heading</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="mh">#cf222e</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* border-bottom: 1px dashed #cf222e; */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c">/* Dark theme */</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">alert-blockquote</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">border-top</span><span class="p">:</span><span class="kc">unset</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* --content-color: #d0d7dd; */</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* --title-background-color: #5151527c; */</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--content-background-color</span><span class="p">:</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">22</span><span class="p">,</span> <span class="mi">37</span><span class="p">,</span> <span class="mi">50</span><span class="p">,</span> <span class="mf">0.8</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">alert-blockquote</span> <span class="p">.</span><span class="nc">alert-heading</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="mh">#58a6ff</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-note</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* --title-background-color: #58a6ff7c; */</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--content-background-color</span><span class="p">:</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">22</span><span class="p">,</span> <span class="mi">37</span><span class="p">,</span> <span class="mi">50</span><span class="p">,</span> <span class="mf">0.8</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-note</span> <span class="p">.</span><span class="nc">alert-heading</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="mh">#58a6ff</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-tip</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* --title-background-color: #82bd8a7c; */</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--content-background-color</span><span class="p">:</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">55</span><span class="p">,</span> <span class="mi">84</span><span class="p">,</span> <span class="mi">56</span><span class="p">,</span> <span class="mf">0.7</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-tip</span> <span class="p">.</span><span class="nc">alert-heading</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="mh">#3fb950</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-important</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* --title-background-color: #9173c57c; */</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--content-background-color</span><span class="p">:</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">46</span><span class="p">,</span> <span class="mi">32</span><span class="p">,</span> <span class="mi">62</span><span class="p">,</span> <span class="mf">0.9</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-important</span> <span class="p">.</span><span class="nc">alert-heading</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="mh">#8d62d8</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-warning</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* --title-background-color: #d1b068a0; */</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--content-background-color</span><span class="p">:</span> <span class="nb">rgb</span><span class="p">(</span><span class="mi">84</span><span class="p">,</span> <span class="mi">68</span><span class="p">,</span> <span class="mi">55</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-warning</span> <span class="p">.</span><span class="nc">alert-heading</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="mh">#d1b271</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-error</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-caution</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* --title-background-color: #c94a43; */</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--content-background-color</span><span class="p">:</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">108</span><span class="p">,</span> <span class="mi">57</span><span class="p">,</span> <span class="mi">54</span><span class="p">,</span> <span class="mf">0.9</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-error</span> <span class="p">.</span><span class="nc">alert-heading</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">alert-blockquote</span><span class="p">.</span><span class="nc">alert-caution</span> <span class="p">.</span><span class="nc">alert-heading</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="mh">#ff9791</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">alert-blockquote</span> <span class="p">.</span><span class="nc">alert-heading</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">background</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">title</span><span class="o">-</span><span class="n">background</span><span class="o">-</span><span class="kc">color</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">alert-blockquote</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">background</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">content</span><span class="o">-</span><span class="n">background</span><span class="o">-</span><span class="kc">color</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">blockquote</span><span class="p">:</span><span class="nd">not</span><span class="o">(</span><span class="p">.</span><span class="nc">alert-blockquote</span><span class="o">)</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="mh">#a02222</span><span class="n">c2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">border-top</span><span class="p">:</span> <span class="mi">2</span><span class="kt">px</span> <span class="kc">solid</span>  <span class="mh">#9c1e1e</span><span class="n">c2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-size</span><span class="p">:</span> <span class="mf">0.9</span><span class="kt">rem</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-style</span><span class="p">:</span> <span class="kc">italic</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>源码也都已经在 Github 中分享。</p>
<h2 id="change-default-renders-style-改变一些默认样式">Change Default Renders&rsquo; Style 改变一些默认样式</h2>
<p>除了上述 markdown 基本单元的渲染调整，表格的样式也不是特别美观，但是由于表格本身的 html 模版已经不在需要调整，因此这里仅对其 css 样式做调整。</p>
<h3 id="tables-表格样式调整">Tables 表格样式调整</h3>
<p>默认的表格本身主要存在以下的一些问题：</p>
<ul>
<li>非全宽&amp;不居中：这里考虑直接调整为全宽；</li>
<li>样式单调：可以按照需求调整为三线表或者调整一下标题栏等；</li>
<li>可以添加 Hover 效果来优化交互；</li>
</ul>
<p>这里通过将 <code>display</code> 调整为 <code>table</code> 来支持全宽，同时通过 <code>overflow</code> 和 <code>wordbreak</code> 等属性来自适应格子宽度避免溢出 <span class="sidenote-number"><small class="sidenote"><a href="https://discourse.gohugo.io/t/responsive-tables-in-markdown/10639/8" target="_blank" rel="noopener">Responsive tables in markdown - support - HUGO</a></small></span> <span class="sidenote-number"><small class="sidenote"><a href="https://stackoverflow.com/questions/19794211/horizontal-scroll-on-overflow-of-table/62451601#62451601" target="_blank" rel="noopener">html - Horizontal scroll on overflow of table - Stack Overflow</a></small></span> ；</p>
<p>样式代码如下，编写的时候要避免 table 属性对其他元素的影响，特别是代码块，因此需要用 not 属性做一些排除：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="c">/* make the table fully wide  &amp; style */</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</span> <span class="nt">table</span><span class="p">:</span><span class="nd">not</span><span class="o">(</span><span class="p">.</span><span class="nc">lntable</span> <span class="p">.</span><span class="nc">highlighttable</span><span class="o">,</span><span class="p">.</span><span class="nc">highlight</span> <span class="nt">table</span><span class="o">,</span><span class="p">.</span><span class="nc">gist</span> <span class="p">.</span><span class="nc">highlight</span><span class="o">)</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="kc">table</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-color</span><span class="p">:</span> <span class="kc">transparent</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">border-radius</span><span class="p">:</span> <span class="mi">6</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">border</span><span class="p">:</span> <span class="mi">1</span><span class="kt">px</span> <span class="kc">solid</span> <span class="kc">black</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">outline</span><span class="p">:</span> <span class="mi">2</span><span class="kt">px</span> <span class="kc">solid</span> <span class="kc">black</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">overflow-x</span><span class="p">:</span> <span class="kc">auto</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">table-layout</span><span class="p">:</span> <span class="kc">fixed</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">word-break</span><span class="p">:</span> <span class="n">break-all</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c">/* responsive ref */</span>
</span></span><span class="line"><span class="cl"><span class="c">/* ref: https://discourse.gohugo.io/t/responsive-tables-in-markdown/10639/8 */</span>
</span></span><span class="line"><span class="cl"><span class="c">/* ref: https://stackoverflow.com/questions/19794211/horizontal-scroll-on-overflow-of-table/62451601#62451601 */</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">post-content</span> <span class="nt">table</span><span class="p">:</span><span class="nd">not</span><span class="o">(</span><span class="p">.</span><span class="nc">lntable</span> <span class="p">.</span><span class="nc">highlighttable</span><span class="o">,</span><span class="p">.</span><span class="nc">highlight</span> <span class="nt">table</span><span class="o">,</span><span class="p">.</span><span class="nc">gist</span> <span class="p">.</span><span class="nc">highlight</span><span class="o">)</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">outline</span><span class="p">:</span> <span class="mi">2</span><span class="kt">px</span> <span class="kc">solid</span> <span class="nb">rgb</span><span class="p">(</span><span class="mi">54</span><span class="p">,</span> <span class="mi">156</span><span class="p">,</span> <span class="mi">95</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</span> <span class="nt">table</span><span class="p">:</span><span class="nd">not</span><span class="o">(</span><span class="p">.</span><span class="nc">lntable</span> <span class="p">.</span><span class="nc">highlighttable</span><span class="o">,</span><span class="p">.</span><span class="nc">highlight</span> <span class="nt">table</span><span class="o">,</span><span class="p">.</span><span class="nc">gist</span> <span class="p">.</span><span class="nc">highlight</span><span class="o">)</span> <span class="nt">thead</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-color</span><span class="p">:</span> <span class="mh">#545d7b</span><span class="mi">8</span><span class="n">a</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">post-content</span> <span class="nt">table</span><span class="p">:</span><span class="nd">not</span><span class="o">(</span><span class="p">.</span><span class="nc">lntable</span> <span class="p">.</span><span class="nc">highlighttable</span><span class="o">,</span><span class="p">.</span><span class="nc">highlight</span> <span class="nt">table</span><span class="o">,</span><span class="p">.</span><span class="nc">gist</span> <span class="p">.</span><span class="nc">highlight</span><span class="o">)</span> <span class="nt">thead</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-color</span><span class="p">:</span> <span class="nb">rgb</span><span class="p">(</span><span class="mi">62</span><span class="p">,</span> <span class="mi">62</span><span class="p">,</span> <span class="mi">62</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</span> <span class="nt">table</span><span class="p">:</span><span class="nd">not</span><span class="o">(</span><span class="p">.</span><span class="nc">lntable</span> <span class="p">.</span><span class="nc">highlighttable</span><span class="o">,</span><span class="p">.</span><span class="nc">highlight</span> <span class="nt">table</span><span class="o">,</span><span class="p">.</span><span class="nc">gist</span> <span class="p">.</span><span class="nc">highlight</span><span class="o">)</span> <span class="nt">td</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</span> <span class="nt">table</span><span class="p">:</span><span class="nd">not</span><span class="o">(</span><span class="p">.</span><span class="nc">lntable</span> <span class="p">.</span><span class="nc">highlighttable</span><span class="o">,</span><span class="p">.</span><span class="nc">highlight</span> <span class="nt">table</span><span class="o">,</span><span class="p">.</span><span class="nc">gist</span> <span class="p">.</span><span class="nc">highlight</span><span class="o">)</span> <span class="nt">tr</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</span> <span class="nt">table</span><span class="p">:</span><span class="nd">not</span><span class="o">(</span><span class="p">.</span><span class="nc">lntable</span> <span class="p">.</span><span class="nc">highlighttable</span><span class="o">,</span><span class="p">.</span><span class="nc">highlight</span> <span class="nt">table</span><span class="o">,</span><span class="p">.</span><span class="nc">gist</span> <span class="p">.</span><span class="nc">highlight</span><span class="o">)</span> <span class="nt">th</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">border-bottom</span><span class="p">:</span> <span class="kc">unset</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">border</span><span class="p">:</span> <span class="mi">1</span><span class="kt">px</span> <span class="kc">solid</span> <span class="kc">black</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</span> <span class="nt">table</span><span class="p">:</span><span class="nd">not</span><span class="o">(</span><span class="p">.</span><span class="nc">lntable</span> <span class="p">.</span><span class="nc">highlighttable</span><span class="o">,</span><span class="p">.</span><span class="nc">highlight</span> <span class="nt">table</span><span class="o">,</span><span class="p">.</span><span class="nc">gist</span> <span class="p">.</span><span class="nc">highlight</span><span class="o">)</span> <span class="nt">td</span><span class="p">:</span><span class="nd">hover</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</span> <span class="nt">table</span><span class="p">:</span><span class="nd">not</span><span class="o">(</span><span class="p">.</span><span class="nc">lntable</span> <span class="p">.</span><span class="nc">highlighttable</span><span class="o">,</span><span class="p">.</span><span class="nc">highlight</span> <span class="nt">table</span><span class="o">,</span><span class="p">.</span><span class="nc">gist</span> <span class="p">.</span><span class="nc">highlight</span><span class="o">)</span> <span class="nt">td</span><span class="p">:</span><span class="nd">focus</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-color</span><span class="p">:</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">170</span><span class="p">,</span> <span class="mi">217</span><span class="p">,</span> <span class="mi">248</span><span class="p">,</span> <span class="mf">0.8</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* transform: scale(1.1); */</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* border: 2px solid black; */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">post-content</span> <span class="nt">table</span><span class="p">:</span><span class="nd">not</span><span class="o">(</span><span class="p">.</span><span class="nc">lntable</span> <span class="p">.</span><span class="nc">highlighttable</span><span class="o">,</span><span class="p">.</span><span class="nc">highlight</span> <span class="nt">table</span><span class="o">,</span><span class="p">.</span><span class="nc">gist</span> <span class="p">.</span><span class="nc">highlight</span><span class="o">)</span> <span class="nt">td</span><span class="p">:</span><span class="nd">hover</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">dark</span> <span class="p">.</span><span class="nc">post-content</span> <span class="nt">table</span><span class="p">:</span><span class="nd">not</span><span class="o">(</span><span class="p">.</span><span class="nc">lntable</span> <span class="p">.</span><span class="nc">highlighttable</span><span class="o">,</span><span class="p">.</span><span class="nc">highlight</span> <span class="nt">table</span><span class="o">,</span><span class="p">.</span><span class="nc">gist</span> <span class="p">.</span><span class="nc">highlight</span><span class="o">)</span> <span class="nt">td</span><span class="p">:</span><span class="nd">focus</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-color</span><span class="p">:</span> <span class="nb">rgb</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.7</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* transform: scale(1.1); */</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* border: 2px solid black; */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="fi">Fi</h2>
<blockquote>
<p>有错误欢迎指正和交流，感兴趣的也欢迎去 github 上点个 star，不胜感激；</p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>调整PaperMod的页面结构以及新增功能</title>
      <link>https://aikenh.cn/posts/%E8%B0%83%E6%95%B4papermod%E7%9A%84%E9%A1%B5%E9%9D%A2%E7%BB%93%E6%9E%84%E4%BB%A5%E5%8F%8A%E6%96%B0%E5%A2%9E%E5%8A%9F%E8%83%BD/</link>
      <pubDate>Sun, 15 Dec 2024 16:52:43 +0000</pubDate>
      <guid>https://aikenh.cn/posts/%E8%B0%83%E6%95%B4papermod%E7%9A%84%E9%A1%B5%E9%9D%A2%E7%BB%93%E6%9E%84%E4%BB%A5%E5%8F%8A%E6%96%B0%E5%A2%9E%E5%8A%9F%E8%83%BD/</guid>
      <description>进一步对PaperMod主题修改，设置侧边目录，侧边导航栏，评论区等功能</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>除了基础的样式和功能，本篇介绍一些会改变原本页面结构的样式调整，或是支持一些除了 markdown 渲染外的一些额外的功能。</p>

</blockquote>
<h2 id="assign-unique-classname-for-pages-给页面注册单独的类名">Assign Unique ClassName for Pages 给页面注册单独的类名</h2>
<p>在进行一些比较复杂的样式设置之前，为了避免样式会影响到预期之外的页面，因此通过 hugo 中的 go-template 语法判断页面类型后，通过修改原有模版，给搜索，时间线，profile 等页面注册一个单独的类名。</p>
<p>修改 <code>themes/PaperMod/layouts/_default/baseof.html</code>，将其中对应部分替换为如下内容：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">body</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;
</span></span></span><span class="line"><span class="cl"><span class="s">{{- if (or (ne .Kind `page` ) (eq .Layout `archives`) (eq .Layout `search`)) -}}
</span></span></span><span class="line"><span class="cl"><span class="s">{{- print &#34;</span><span class="na">list</span><span class="err">&#34;</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl"><span class="err">{{</span><span class="na">-</span> <span class="na">end</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl"><span class="err">{{</span><span class="na">-</span> <span class="na">if</span> <span class="na">eq</span> <span class="err">.</span><span class="na">Type</span> <span class="err">`</span><span class="na">linklog</span><span class="err">`</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl"><span class="err">{{</span><span class="na">-</span> <span class="na">print</span> <span class="err">&#34;</span><span class="na">-linklog-</span><span class="err">&#34;</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl"><span class="err">{{</span><span class="na">-</span> <span class="na">end</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl"><span class="err">{{</span><span class="na">-</span> <span class="na">if</span> <span class="na">eq</span> <span class="err">.</span><span class="na">Layout</span> <span class="err">`</span><span class="na">search</span><span class="err">`</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl"><span class="err">{{</span><span class="na">-</span> <span class="na">print</span> <span class="err">&#34;</span> <span class="na">search</span><span class="err">&#34;</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl"><span class="err">{{</span><span class="na">-</span> <span class="na">end</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl"><span class="err">{{</span><span class="na">-</span> <span class="na">if</span> <span class="err">(</span><span class="na">eq</span> <span class="err">.</span><span class="na">Layout</span> <span class="err">`</span><span class="na">archives</span><span class="err">`)</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl"><span class="err">{{</span><span class="na">-</span> <span class="na">print</span> <span class="err">&#34;</span><span class="na">-archive</span><span class="err">&#34;</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl"><span class="err">{{</span><span class="na">-</span> <span class="na">end</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl"><span class="err">{{</span><span class="na">-</span> <span class="na">if</span> <span class="err">.</span><span class="na">IsHome</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl"><span class="err">{{</span><span class="na">-</span> <span class="na">print</span> <span class="err">&#34;</span><span class="na">-profile</span><span class="err">&#34;</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl"><span class="err">{{</span><span class="na">-</span> <span class="na">end</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl"><span class="err">{{</span><span class="na">-</span> <span class="na">if</span> <span class="na">not</span> <span class="err">.</span><span class="na">IsHome</span> <span class="err">|</span> <span class="na">and</span> <span class="err">.</span><span class="na">Title</span> <span class="err">|</span> <span class="na">and</span> <span class="err">.</span><span class="na">Description</span> <span class="err">}}</span>
</span></span><span class="line"><span class="cl"><span class="err">{{</span><span class="na">-</span> <span class="na">print</span> <span class="err">&#34;</span><span class="na">post</span><span class="err">&#34;</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl"><span class="err">{{</span><span class="na">-</span> <span class="na">end</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl"><span class="err">{{</span><span class="na">-</span> <span class="na">if</span> <span class="na">eq</span> <span class="na">site</span><span class="err">.</span><span class="na">Params</span><span class="err">.</span><span class="na">defaultTheme</span> <span class="err">`</span><span class="na">dark</span><span class="err">`</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl"><span class="err">{{</span><span class="na">-</span> <span class="na">print</span> <span class="err">&#34;</span> <span class="na">dark</span><span class="err">&#34;</span> <span class="err">}}</span>
</span></span><span class="line"><span class="cl"><span class="err">{{</span><span class="na">-</span> <span class="na">end</span> <span class="na">-</span><span class="err">}}</span>
</span></span><span class="line"><span class="cl"><span class="err">&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;top&#34;</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>替换即可通过如下的 class 对页面进行索引：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: center">Selector</th>
          <th style="text-align: center">Page</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: center">.list-linklog-post</td>
          <td style="text-align: center">linklog 页面</td>
      </tr>
      <tr>
          <td style="text-align: center">.list.search</td>
          <td style="text-align: center">search 界面</td>
      </tr>
      <tr>
          <td style="text-align: center">.list-archive</td>
          <td style="text-align: center">archive 界面</td>
      </tr>
      <tr>
          <td style="text-align: center">.list-profile</td>
          <td style="text-align: center">主页</td>
      </tr>
  </tbody>
</table>
<p>在上述页面选择器之后添加 <code>.dark</code> 即可定位对应的深色主题样式，这部分可以按照自己的习惯去随便修改即可。</p>
<h3 id="background-image-设置背景">Background Image 设置背景</h3>
<p>可以参考笔者的设置，给背景添加一层简单的遮罩，具体代码如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">#</span><span class="nn">top</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">list</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">list-profile</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-image</span><span class="p">:</span> <span class="nb">url</span><span class="p">(</span><span class="sx">/cover/cover1.jpeg</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-size</span><span class="p">:</span> <span class="kc">cover</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-repeat</span><span class="p">:</span> <span class="kc">no-repeat</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-attachment</span><span class="p">:</span> <span class="kc">fixed</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">#</span><span class="nn">top</span><span class="p">.</span><span class="nc">dark</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">list</span><span class="p">.</span><span class="nc">dark</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">list-profile</span><span class="p">.</span><span class="nc">dark</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-image</span><span class="p">:</span> <span class="nb">url</span><span class="p">(</span><span class="sx">/cover/cover0.jpeg</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">#</span><span class="nn">top</span><span class="p">::</span><span class="nd">after</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">list</span><span class="p">::</span><span class="nd">after</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">list-profile</span><span class="p">::</span><span class="nd">after</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">background</span><span class="p">:</span> <span class="kc">inherit</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">filter</span><span class="p">:</span> <span class="nb">blur</span><span class="p">(</span><span class="mi">5</span><span class="kt">px</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">content</span><span class="p">:</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">position</span><span class="p">:</span> <span class="kc">fixed</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">top</span><span class="p">:</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">left</span><span class="p">:</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">width</span><span class="p">:</span> <span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">min-height</span><span class="p">:</span> <span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-size</span><span class="p">:</span> <span class="kc">cover</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">z-index</span><span class="p">:</span> <span class="mi">-1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-attachment</span><span class="p">:</span> <span class="kc">fixed</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果后续由于背景图像的色块比较杂乱，会导致文本模糊不清，可以给文本区域添加底色和对应的毛玻璃特效如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">list-archive</span> <span class="p">.</span><span class="nc">main</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">list-linklog-post</span> <span class="p">.</span><span class="nc">main</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="p">#</span><span class="nn">top</span> <span class="nt">article</span><span class="p">.</span><span class="nc">post-single</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kp">-webkit-</span><span class="n">backdrop-filter</span><span class="p">:</span> <span class="nb">blur</span><span class="p">(</span><span class="mi">30</span><span class="kt">px</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="n">backdrop-filter</span><span class="p">:</span> <span class="nb">blur</span><span class="p">(</span><span class="mi">30</span><span class="kt">px</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-color</span><span class="p">:</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">104</span><span class="p">,</span> <span class="mi">152</span><span class="p">,</span> <span class="mi">191</span><span class="p">,</span> <span class="mf">0.45</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>完成了基础设置之后就可以开始对页面结构做调整了，接下来主要介绍一下侧边目录、侧边导航栏，以及新建分享页面三个部分的页面调整和页面新增。</p>
<h2 id="support-linklog-page-添加博文收藏界面">Support LinkLog Page 添加博文收藏界面</h2>
<p>受到 <a href="https://xiaofei.ge/posts/modify-hugo-papermod-theme-and-templates/" target="_blank" rel="noopener">Xiaofei Ge</a>
 <span class="sidenote-number"><small class="sidenote"><a href="https://xiaofei.ge/linklog/" target="_blank" rel="noopener">Linklog | Xiaofei Ge</a></small></span> 的启发，确实希望能有一个页面来专门存放一些自己喜欢或者希望存档的文章，通过直接跳转或者表明转载（防止原博挂掉）的方式进行收藏，避免和自己的文章混在一起。</p>
<p>参考 <a href="https://dannorth.net/hugo-redirects/" target="_blank" rel="noopener">Using Hugo as a redirect service - Dan North &amp; Associates Limited</a>
，设计对应收藏博文的 markdown 元信息应该如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">title</span><span class="p">:</span><span class="w"> </span><span class="l">「特别篇」在关闭光猫、路由器IPv6防火墙后可能遇到的安全问题</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">url</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;www.bilibili.com/opus/825167559504429056&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">date</span><span class="p">:</span><span class="w"> </span><span class="ld">2023-11-05</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">draft</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;linklog&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">author</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;ce-12&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>通过 type 定义页面类型，日期存储我们收藏的时间，url 则是核心的跳转页面，还有一些作者和 title 的展示信息，并在 archive 按照日期展示每一条链接。</p>
<p>因此借助 GPT 快速实现了一版，并调整了一下搜索代码，使得搜索到 Linklog 文章的时候，会有符号&amp;样式去标识其为外部跳转的博文。</p>
<h3 id="add-linklog-page-添加博文收藏界面">Add LinkLog Page 添加博文收藏界面</h3>
<p>上述说到希望以 archive 界面的形式来收藏博文，通过简单的标题和简介来记录对应的博文，以及存放博文的时间，因此参考 <code>/layouts/_default/archives.html</code> 创建 <code>layouts/linklog/list.html</code> 如下，定义 LinkLog 的界面.</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">{{- define &#34;main&#34; }}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">header</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;page-header&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span>{{ .Title }}<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  {{- if .Description }}
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;post-description&#34;</span><span class="p">&gt;</span>{{ .Description }}<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  {{- end }}
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">header</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">{{- $linklogPages := where site.RegularPages &#34;Type&#34; &#34;linklog&#34; }} <span class="c">&lt;!-- Adjust this if necessary --&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">{{- range $linklogPages.GroupByPublishDate &#34;2006&#34; }}
</span></span><span class="line"><span class="cl">{{- if ne .Key &#34;0001&#34; }}
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;archive-year&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  {{- $year := replace .Key &#34;0001&#34; &#34;&#34; }}
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">h2</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;archive-year-header&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;{{ $year }}&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;archive-header-link&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;#{{ $year }}&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      {{- $year -}}
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">sup</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;archive-count&#34;</span><span class="p">&gt;</span><span class="ni">&amp;nbsp;</span>{{ len .Pages }}<span class="p">&lt;/</span><span class="nt">sup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">h2</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  {{- range .Pages.GroupByDate &#34;January&#34; }}
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;archive-month&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">h3</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;archive-month-header&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;{{ $year }}-{{ .Key }}&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;archive-header-link&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;#{{ $year }}-{{ .Key }}&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        {{- .Key -}}
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">sup</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;archive-count&#34;</span><span class="p">&gt;</span><span class="ni">&amp;nbsp;</span>{{ len .Pages }}<span class="p">&lt;/</span><span class="nt">sup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;archive-posts&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      {{- range .Pages }}
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;archive-entry&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">h3</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;archive-entry-title&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          {{- if .Params.url}}
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;jump-icon&#34;</span><span class="p">&gt;&lt;</span><span class="nt">ion-icon</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;link-outline&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">ion-icon</span><span class="p">&gt;&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://{{ .Params.url }}&#34;</span> <span class="na">target</span><span class="o">=</span><span class="s">&#34;_blank&#34;</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;noopener noreferrer&#34;</span><span class="p">&gt;</span>{{ .Title }}<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span> <span class="c">&lt;!-- Prepend the protocol --&gt;</span>
</span></span><span class="line"><span class="cl">          {{- else}}
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;{{ .Permalink }}&#34;</span> <span class="p">&gt;</span>转) {{ .Title }}<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span> <span class="c">&lt;!-- Prepend the protocol --&gt;</span>
</span></span><span class="line"><span class="cl">          {{- end}}
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        {{- if .Params.description }} <span class="c">&lt;!-- Check if description exists --&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;archive-entry-description&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          {{ .Params.description }} <span class="c">&lt;!-- Display the description --&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        {{- end }}
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;archive-meta&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          {{- partial &#34;post_meta.html&#34; . -}} <span class="c">&lt;!-- Optional: Include meta info --&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      {{- end }}
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  {{- end }}
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">{{- end }}
</span></span><span class="line"><span class="cl">{{- end }}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">{{- end }}{{/* end main */}}</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>其中根据页面元信息是否存在 url 决定是否是外部链接，来决定 title 前面的样式是跳转符号还是转载标识，随后设置跳转标识的样式如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">jump-icon</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">position</span><span class="p">:</span> <span class="kc">relative</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">top</span><span class="p">:</span><span class="mi">3</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">padding-right</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span> <span class="c">/* Space between the icon and the title */</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-size</span><span class="p">:</span> <span class="mi">1</span><span class="kt">em</span><span class="p">;</span> <span class="c">/* Adjust size as needed */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">#</span><span class="nn">search-link</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">text-decoration</span><span class="p">:</span> <span class="kc">underline</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="kc">slateblue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">list-linklog-post</span> <span class="p">.</span><span class="nc">archive-entry-description</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">secondary</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>设置完成后，即可在 content 中新建 linklog 文件夹，并在其中存放对应的转载文章，例如 <code>linklog/example.md</code> ，然后填写上述我们设计的格式，尝试跳转效果。最终页面效果如下：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241220222745.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241220222745.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241220222745.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>外部链接点击后即可跳转到对应的博文。</p>
<h3 id="avoid-url-directly-visit-wrong-page-避免直接用-url-访问对应页面时出现空页面">Avoid Url Directly Visit Wrong Page 避免直接用 url 访问对应页面时出现空页面</h3>
<p>添加 <code>layouts/linklog/single.html</code> 来设置页面的重定向，避免直接输入 linklog 对应地址以后，跳转到了一个空的 markdown 页面，具体代码如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">{{- define &#34;main&#34; }}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">{{- if .Params.url }}
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">meta</span> <span class="na">http-equiv</span><span class="o">=</span><span class="s">&#34;refresh&#34;</span> <span class="na">content</span><span class="o">=</span><span class="s">&#34;0; url=https://{{ .Params.url }}&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">href</span> <span class="o">=</span> <span class="s2">&#34;https://{{ .Params.url }}&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span>Redirecting...<span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>If you are not redirected, <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://{{ .Params.url }}&#34;</span><span class="p">&gt;</span>click here<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>.<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">{{- else }}
</span></span><span class="line"><span class="cl">....
</span></span><span class="line"><span class="cl">{{- end }}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">{{- end }}{{/* end main */}}</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>通过判断参数中是否存在 url 来设置是否执行跳转，否则则使用默认的 <code>single.html</code> 的方式渲染 markdown 的转载文章。 <span class="sidenote-number"><small class="sidenote">else 中省略的部分填写的是 <code>_dafault/single.html</code></small></span> 中的内容。</p>
<h3 id="add-diff-style-in-search-result-搜索结果中支持跳转和特殊样式">Add Diff Style in Search Result 搜索结果中支持跳转和特殊样式</h3>
<p>由于在搜索中可能会搜到对应的文章，这里也需要和普通的文章做一些区分，因此修改 <code>assets/js/fastsearch.js</code> 的搜索结果部分如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="err">/ execute search as each character is typed</span>
</span></span><span class="line"><span class="cl"><span class="nx">sInput</span><span class="p">.</span><span class="nx">onkeyup</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// run a search query (for &#34;term&#34;) every time a letter is typed
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">// in the search box
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">if</span> <span class="p">(</span><span class="nx">fuse</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nx">results</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nx">params</span><span class="p">.</span><span class="nx">fuseOpts</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">results</span> <span class="o">=</span> <span class="nx">fuse</span><span class="p">.</span><span class="nx">search</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">value</span><span class="p">.</span><span class="nx">trim</span><span class="p">(),</span> <span class="p">{</span><span class="nx">limit</span><span class="o">:</span> <span class="nx">params</span><span class="p">.</span><span class="nx">fuseOpts</span><span class="p">.</span><span class="nx">limit</span><span class="p">});</span> <span class="c1">// the actual query being run using fuse.js along with options
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">results</span> <span class="o">=</span> <span class="nx">fuse</span><span class="p">.</span><span class="nx">search</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">value</span><span class="p">.</span><span class="nx">trim</span><span class="p">());</span> <span class="c1">// the actual query being run using fuse.js
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nx">results</span><span class="p">.</span><span class="nx">length</span> <span class="o">!==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// build our html if result exists
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="kd">let</span> <span class="nx">resultSet</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">;</span> <span class="c1">// our results bucket
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">            <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">item</span> <span class="k">in</span> <span class="nx">results</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="kr">const</span> <span class="nx">permalink</span> <span class="o">=</span> <span class="nx">results</span><span class="p">[</span><span class="nx">item</span><span class="p">].</span><span class="nx">item</span><span class="p">.</span><span class="nx">permalink</span><span class="p">;</span> <span class="c1">// Get the permalink
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>                
</span></span><span class="line"><span class="cl">                <span class="kr">const</span> <span class="nx">url</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">URL</span><span class="p">(</span><span class="nx">permalink</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="kr">const</span> <span class="nx">pathAfterDomain</span> <span class="o">=</span> <span class="nx">url</span><span class="p">.</span><span class="nx">pathname</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Permalink:&#34;</span><span class="p">,</span> <span class="nx">permalink</span><span class="p">);</span> <span class="c1">// Log the permalink
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">                <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Last Segment:&#34;</span><span class="p">,</span> <span class="nx">pathAfterDomain</span><span class="p">);</span> <span class="c1">// Log the last segment
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>                <span class="c1">// Check if the last segment contains a period
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>                <span class="kr">const</span> <span class="nx">jumpIcon</span> <span class="o">=</span> <span class="nx">pathAfterDomain</span><span class="p">.</span><span class="nx">includes</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="p">)</span> <span class="o">?</span> <span class="s1">&#39;&lt;span class=&#34;jump-icon&#34;&gt;&lt;ion-icon name=&#34;link-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/span&gt;&#39;</span> <span class="o">:</span> <span class="s1">&#39;&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                
</span></span><span class="line"><span class="cl">                <span class="k">if</span> <span class="p">(</span><span class="nx">pathAfterDomain</span><span class="p">.</span><span class="nx">includes</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="nx">resultSet</span> <span class="o">+=</span> <span class="sb">`&lt;li class=&#34;post-entry&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="sb">                        &lt;header class=&#34;entry-header&#34; id=&#34;search-link&#34;&gt;</span><span class="si">${</span><span class="nx">jumpIcon</span><span class="si">}${</span><span class="nx">results</span><span class="p">[</span><span class="nx">item</span><span class="p">].</span><span class="nx">item</span><span class="p">.</span><span class="nx">title</span><span class="si">}</span><span class="sb">&amp;nbsp;»&lt;/header&gt;
</span></span></span><span class="line"><span class="cl"><span class="sb">                        &lt;a href=&#34;</span><span class="si">${</span><span class="nx">permalink</span><span class="si">}</span><span class="sb">&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34; aria-label=&#34;</span><span class="si">${</span><span class="nx">results</span><span class="p">[</span><span class="nx">item</span><span class="p">].</span><span class="nx">item</span><span class="p">.</span><span class="nx">title</span><span class="si">}</span><span class="sb">&#34;&gt;&lt;/a&gt;
</span></span></span><span class="line"><span class="cl"><span class="sb">                    &lt;/li&gt;`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">                <span class="k">else</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="nx">resultSet</span> <span class="o">+=</span> <span class="sb">`&lt;li class=&#34;post-entry&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="sb">                        &lt;header class=&#34;entry-header&#34;&gt;</span><span class="si">${</span><span class="nx">jumpIcon</span><span class="si">}${</span><span class="nx">results</span><span class="p">[</span><span class="nx">item</span><span class="p">].</span><span class="nx">item</span><span class="p">.</span><span class="nx">title</span><span class="si">}</span><span class="sb">&amp;nbsp;»&lt;/header&gt;
</span></span></span><span class="line"><span class="cl"><span class="sb">                        &lt;a href=&#34;</span><span class="si">${</span><span class="nx">permalink</span><span class="si">}</span><span class="sb">&#34; aria-label=&#34;</span><span class="si">${</span><span class="nx">results</span><span class="p">[</span><span class="nx">item</span><span class="p">].</span><span class="nx">item</span><span class="p">.</span><span class="nx">title</span><span class="si">}</span><span class="sb">&#34;&gt;&lt;/a&gt;
</span></span></span><span class="line"><span class="cl"><span class="sb">                    &lt;/li&gt;`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="nx">resList</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="nx">resultSet</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="nx">resultsAvailable</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="nx">first</span> <span class="o">=</span> <span class="nx">resList</span><span class="p">.</span><span class="nx">firstChild</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="nx">last</span> <span class="o">=</span> <span class="nx">resList</span><span class="p">.</span><span class="nx">lastChild</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">resultsAvailable</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="nx">resList</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>由于在之前的设置下，通过判断搜索结果的跳转链接在我们域名之后是否还存在 <code>.</code> 来判断其是否为外部链接，进而为其添加跳转标识即可，最终效果如下：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241220222656.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241220222656.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241220222656.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="side-toc-宽屏下设置侧边目录">Side Toc 宽屏下设置侧边目录</h2>
<p>正如以往笔者的 hexo 博客的设置，将目录放到侧边，一是能优化 PaperMod 主题在宽屏时对空间的利用，二是能够方便阅读的时候进行章节的跳转以及对进度的提示，因此下定决心在页面较宽时将目录改至侧边。</p>
<p>实现的方案主要借鉴自<a href="https://www.zhouxin.space/logs/introduce-side-toc-and-reading-percentage-to-papermod/" target="_blank" rel="noopener">周鑫的个人博客</a>
，在此之上添加了以下的一些特性：</p>
<ol>
<li>为已读的内容添加 read 的类名，设置不同的样式；</li>
<li>在加密页面隐藏 toc</li>
<li>仅展开当前正在阅读的章节的子章节</li>
<li>添加 toc 中 H2 的 index</li>
</ol>
<p>这里仅额外介绍一下改动部分，<strong>最终的源码可从 Github 上获取</strong> <span class="sidenote-number"><small class="sidenote"><a href="https://github.com/AikenH/papermod-sidebar/blob/master/layouts/partials/toc.html" target="_blank" rel="noopener">papermod-sidebar/layouts/partials/toc.html · AikenH/papermod-sidebar</a></small></span> <span class="sidenote-number"><small class="sidenote"><a href="https://github.com/AikenH/papermod-sidebar/blob/master/assets/css/common/toc.css" target="_blank" rel="noopener">papermod-sidebar/assets/css/common/toc.css · AikenH/papermod-sidebar</a></small></span></p>
<blockquote>
<p>本博客的回到顶部也是基于周鑫的实现完成，这里不在赘述，可以自行前往参考。</p>
</blockquote>
<h3 id="diff-style-for-read--unread-基于阅读状态修改样式">Diff Style for Read &amp; Unread 基于阅读状态修改样式</h3>
<p>在周鑫的实现中 <code>toc.html</code> 的滚动函数部分首先添加 read 状态的重置，避免回滚时的样式错误：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">window.addEventListener(&#39;scroll&#39;, () =&gt; {
</span></span><span class="line"><span class="cl">	// Get the current scroll position
</span></span><span class="line"><span class="cl">	const scrollPosition = window.pageYOffset || document.documentElement.scrollTop;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	// Check if the scroll position is at the top of the page
</span></span><span class="line"><span class="cl">	if (scrollPosition === 0) {
</span></span><span class="line"><span class="cl">		return;
</span></span><span class="line"><span class="cl">	}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	// Ensure elements is a valid NodeList
</span></span><span class="line"><span class="cl">	// ---------------------状态重置添加位置
</span></span><span class="line"><span class="cl">	if (elements <span class="err">&amp;&amp;</span> elements.length &gt; 0) {
</span></span><span class="line"><span class="cl">		elements.forEach(element =&gt; {
</span></span><span class="line"><span class="cl">			const id = encodeURI(element.getAttribute(&#39;id&#39;)).toLowerCase();
</span></span><span class="line"><span class="cl">			const tocLink = document.querySelector(`.inner ul li a[href=&#34;#${id}&#34;]`);
</span></span><span class="line"><span class="cl">			tocLink.classList.remove(&#39;read&#39;);
</span></span><span class="line"><span class="cl">		});
</span></span><span class="line"><span class="cl">	 // --------------------------------------------
</span></span><span class="line"><span class="cl">		// Check if there is an object in the top half of the screen or keep the last item active
</span></span><span class="line"><span class="cl">		...
</span></span><span class="line"><span class="cl">		...</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>然后再滚动判断 active 元素的部分添加 read 属性的赋值：添加如下 3 行即可</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">elements.forEach((element, index) =&gt; {
</span></span><span class="line"><span class="cl">	const id = encodeURI(element.getAttribute(&#39;id&#39;)).toLowerCase();
</span></span><span class="line"><span class="cl">	const tocLink = document.querySelector(`.inner ul li a[href=&#34;#${id}&#34;]`);
</span></span><span class="line"><span class="cl">	if (element === activeElement){
</span></span><span class="line"><span class="cl">		tocLink.classList.add(&#39;active&#39;);
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		// Ensure the active element is in view within the .inner container
</span></span><span class="line"><span class="cl">		const tocContainer = document.querySelector(&#39;.toc .inner&#39;);
</span></span><span class="line"><span class="cl">		const linkOffsetTop = tocLink.offsetTop;
</span></span><span class="line"><span class="cl">		const containerHeight = tocContainer.clientHeight;
</span></span><span class="line"><span class="cl">		const linkHeight = tocLink.clientHeight;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		// Calculate the scroll position to center the active link
</span></span><span class="line"><span class="cl">		const scrollPosition = linkOffsetTop - (containerHeight / 2) + (linkHeight / 2);
</span></span><span class="line"><span class="cl">		tocContainer.scrollTo({ top: scrollPosition, behavior: &#39;smooth&#39; });
</span></span><span class="line"><span class="cl">	} else {
</span></span><span class="line"><span class="cl">		// ------------------添加部分---------------------
</span></span><span class="line"><span class="cl">		if (getOffsetTop(element) <span class="p">&lt;</span> <span class="nt">scrollPosition</span><span class="err">)</span> <span class="err">{</span>
</span></span><span class="line"><span class="cl">			<span class="na">tocLink</span><span class="err">.</span><span class="na">classList</span><span class="err">.</span><span class="na">add</span><span class="err">(&#39;</span><span class="na">read</span><span class="err">&#39;);</span> <span class="err">//</span> <span class="na">Mark</span> <span class="na">as</span> <span class="na">read</span>
</span></span><span class="line"><span class="cl">		<span class="err">}</span>
</span></span><span class="line"><span class="cl">		<span class="err">//</span> <span class="na">------------------添加部分---------------------</span>
</span></span><span class="line"><span class="cl">		<span class="na">tocLink</span><span class="err">.</span><span class="na">classList</span><span class="err">.</span><span class="na">remove</span><span class="err">(&#39;</span><span class="na">active</span><span class="err">&#39;);</span>
</span></span><span class="line"><span class="cl">	<span class="err">}</span>
</span></span><span class="line"><span class="cl"><span class="err">});</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><code>toc.css</code> 中对 read 添加样式</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">read</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">color</span><span class="p">:</span> <span class="nb">rgb</span><span class="p">(</span><span class="mi">105</span><span class="p">,</span> <span class="mi">105</span><span class="p">,</span> <span class="mi">105</span><span class="p">)</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="only-unfold-current-chapter-自动折叠其他章节">Only Unfold Current Chapter 自动折叠其他章节</h3>
<p>在 <code>layouts/partials/head.html</code> 中添加如下代码</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">{{ if or .Params.autofoldtoc .Page.Site.Params.autofoldtoc }}
</span></span><span class="line"><span class="cl">    {{ $styles := resources.Get &#34;css/autofoldtoc.css.tmpl&#34; | resources.ExecuteAsTemplate &#34;autofoldtoc.css&#34; . }}
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span><span class="err">{</span> <span class="err">$styles.Content</span> <span class="err">|</span> <span class="err">safeCSS</span> <span class="p">}</span><span class="err">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">{{ end }}</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>使得页面在设置了 <code>autofoldtoc</code> 时，引入我们预先定义好的样式表，实现对非激活章节的折叠，然后在 <code>assets.css</code> 中新建 <code>autofoldtoc.css.tmpl</code> 预先定义折叠样式<span class="sidenote-number"><small class="sidenote"><a href="https://blog.csdn.net/DuChongYY/article/details/136244762" target="_blank" rel="noopener">为Hugo主题添加动态跟随目录Scrollspy效果</a></small></span>如下</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">toc-container</span><span class="p">.</span><span class="nc">wide</span> <span class="nt">li</span><span class="o">&gt;</span><span class="nt">ul</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">display</span><span class="p">:</span> <span class="kc">none</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">toc-container</span><span class="p">.</span><span class="nc">wide</span> <span class="nt">li</span><span class="p">:</span><span class="nd">has</span><span class="o">(</span><span class="nt">a</span><span class="p">.</span><span class="nc">active</span><span class="o">)</span> <span class="nt">ul</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">display</span><span class="p">:</span> <span class="kc">inherit</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>后续可以在 <code>hugo.yaml</code> 中设置如下开启<strong>全局</strong>目录自动折叠功能</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">params</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">autofoldtoc</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>或者在 markdown 的 meta-info 中添加如下一行即可<strong>针对单篇文章</strong>开启。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">autofoldtoc</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="hide-toc-before-decrypt-博文解密之前隐藏目录">Hide Toc before Decrypt 博文解密之前隐藏目录</h3>
<p>修改 <code>toc.html</code> 的 <code>getOffsetTop</code> 如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">getOffsetTop</span><span class="p">(</span><span class="nx">element</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">element</span><span class="p">.</span><span class="nx">getClientRects</span><span class="p">().</span><span class="nx">length</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s1">&#39;.hugo-encryptor-prompt&#39;</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="nx">elements</span><span class="p">.</span><span class="nx">length</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// Re-query the elements if the class is not found
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="nx">elements</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelectorAll</span><span class="p">(</span><span class="s1">&#39;h1[id],h2[id],h3[id],h4[id],h5[id],h6[id]&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// console.log(&#39;Elements re-queried:&#39;, elements);
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">rect</span> <span class="o">=</span> <span class="nx">element</span><span class="p">.</span><span class="nx">getBoundingClientRect</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">win</span> <span class="o">=</span> <span class="nx">element</span><span class="p">.</span><span class="nx">ownerDocument</span><span class="p">.</span><span class="nx">defaultView</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">rect</span><span class="p">.</span><span class="nx">top</span> <span class="o">+</span> <span class="nx">win</span><span class="p">.</span><span class="nx">pageYOffset</span><span class="p">;</span>   
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这一部分后面使用简码加密的会讲到，实际上是一个伪加密，只是不显示对应模块罢了。</p>
<h3 id="auto-index-添加章节计数">Auto Index 添加章节计数</h3>
<p><code>toc.css</code> 中设置 H2 的样式如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">toc</span> <span class="p">.</span><span class="nc">inner</span> <span class="o">&gt;</span> <span class="nt">ul</span> <span class="o">&gt;</span> <span class="nt">li</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">list-style</span><span class="p">:</span> <span class="kc">none</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">counter-increment</span><span class="p">:</span> <span class="n">toc-section</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">toc</span> <span class="p">.</span><span class="nc">inner</span> <span class="o">&gt;</span> <span class="nt">ul</span> <span class="o">&gt;</span> <span class="nt">li</span><span class="p">::</span><span class="nd">before</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">content</span><span class="p">:</span> <span class="nb">counter</span><span class="p">(</span><span class="n">toc</span><span class="o">-</span><span class="n">section</span><span class="p">)</span> <span class="s1">&#39;.&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">margin-right</span><span class="p">:</span> <span class="mf">0.4</span><span class="kt">em</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="sidebar-宽屏下设置侧边导航栏">Sidebar 宽屏下设置侧边导航栏</h2>
<p>在默认的 nav 之外添加一个 sidebar 结构体，然后通过 css 在不同的视窗中启用不同的导航栏即可，sidebar 可以添加在 <code>layouts/partials/header.html</code> 中：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">header</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">...
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">header</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">{{- $iconMap := dict &#34;home&#34; &#34;home-outline&#34; &#34;posts&#34; &#34;newspaper-outline&#34; &#34;tags&#34; &#34;pricetags-outline&#34; &#34;categories&#34;
</span></span><span class="line"><span class="cl">&#34;grid-outline&#34; &#34;archives&#34; &#34;folder-outline&#34; &#34;search&#34; &#34;search&#34; &#34;about&#34; &#34;person&#34; &#34;linklog&#34; &#34;link&#34;}}
</span></span><span class="line"><span class="cl">{{- $bgColorMap := dict &#34;home&#34; &#34;#f44336&#34; &#34;posts&#34; &#34;#b145e9&#34; &#34;tags&#34; &#34;#0f93c7&#34; &#34;categories&#34; &#34;#ffa117&#34; &#34;archives&#34; &#34;#0fc70f&#34;
</span></span><span class="line"><span class="cl">&#34;search&#34; &#34;#15c095&#34; &#34;about&#34; &#34;#d16111&#34; &#34;linklog&#34; &#34;#0fc70f&#34;}}
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;sidebar&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">li</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;logo&#34;</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;--bg: #333;&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;#&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;logo-icon&#34;</span><span class="p">&gt;&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;/logo/logo.png&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;logo-text&#34;</span><span class="p">&gt;</span>Aiken&#39;s Blog <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;menulist&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            {{- range site.Menus.main }}
</span></span><span class="line"><span class="cl">            {{- $menu_item_url := (cond (strings.HasSuffix .URL &#34;/&#34;) .URL (printf &#34;%s/&#34; .URL) ) | absLangURL }}
</span></span><span class="line"><span class="cl">            {{- $page_url:= $currentPage.Permalink | absLangURL }}
</span></span><span class="line"><span class="cl">            {{- $is_search := eq (site.GetPage .KeyName).Layout `search` }}
</span></span><span class="line"><span class="cl">            {{- $iconName := index $iconMap .Name }}
</span></span><span class="line"><span class="cl">            {{- $bgColor := index $bgColorMap .Name }}
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">li</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;{{- if eq $menu_item_url $page_url }}active{{- end }}&#34;</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;--bg: {{ $bgColor }};&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;{{ .URL | absLangURL }}&#34;</span> <span class="na">title</span><span class="o">=</span><span class="s">&#34;{{ .Title | default .Name }} {{- cond $is_search (&#34;</span> <span class="err">(</span><span class="na">Alt</span> <span class="err">+</span> <span class="err">/)&#34;</span> <span class="err">|</span> <span class="na">safeHTMLAttr</span><span class="err">)</span> <span class="err">(&#34;&#34;</span> <span class="err">|</span> <span class="na">safeHTMLAttr</span> <span class="err">)</span> <span class="err">}}&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="err">{{</span><span class="na">-</span> <span class="na">cond</span> <span class="err">$</span><span class="na">is_search</span> <span class="err">(&#34;</span> <span class="na">accesskey</span><span class="o">=</span><span class="s">/&#34;</span> <span class="err">|</span> <span class="na">safeHTMLAttr</span><span class="err">)</span> <span class="err">(&#34;&#34;</span> <span class="err">|</span> <span class="na">safeHTMLAttr</span> <span class="err">)</span> <span class="err">}}</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;logo-icon&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                        <span class="p">&lt;</span><span class="nt">ion-icon</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;{{ $iconName }}&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">ion-icon</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;logo-text&#34;</span><span class="p">&gt;</span>{{ .Name }}<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            {{- end }}
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;logo-switches&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">button</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;theme-toggle&#34;</span> <span class="na">accesskey</span><span class="o">=</span><span class="s">&#34;t&#34;</span> <span class="na">title</span><span class="o">=</span><span class="s">&#34;(Alt +T)&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;logo-icon&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;moon&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                        <span class="p">&lt;</span><span class="nt">ion-icon</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;moon-outline&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">ion-icon</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;logo-icon&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;sun&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                        <span class="p">&lt;</span><span class="nt">ion-icon</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;sunny-outline&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">ion-icon</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>然后通过 css 去控制 sidebar 的位置和基本样式即可，这里的样式是来自之前自己<a href="https://github.com/AikenH/myWebProj/tree/side-nav" target="_blank" rel="noopener">练手项目</a>
，这里就不再详细分享：</p>
<p>基本的一些设置，包括 hover，nav 和 sidebar 的切换部分的 css 如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="c">/* sidebar styles */</span>
</span></span><span class="line"><span class="cl"><span class="p">@</span><span class="k">media</span> <span class="nt">screen</span> <span class="nt">and</span> <span class="o">(</span><span class="nt">min-width</span><span class="o">:</span> <span class="nt">768px</span><span class="o">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nc">nav</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">display</span><span class="p">:</span> <span class="kc">none</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c">/* @media screen and (min-width: 768px) and (max-width: 1600px){
</span></span></span><span class="line"><span class="cl"><span class="c">  .main:has(&gt;article:first-child){
</span></span></span><span class="line"><span class="cl"><span class="c">    margin-left: 80px;
</span></span></span><span class="line"><span class="cl"><span class="c">  }
</span></span></span><span class="line"><span class="cl"><span class="c">} */</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">sidebar</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* background-color: var(--para-color); */</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-color</span><span class="p">:</span> <span class="mh">#abc3d1</span><span class="n">bb</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">opacity</span><span class="p">:</span> <span class="mf">0.9</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">position</span><span class="p">:</span> <span class="kc">fixed</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">padding-top</span><span class="p">:</span> <span class="mi">0</span><span class="kt">vh</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">padding-left</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">height</span><span class="p">:</span> <span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">width</span><span class="p">:</span> <span class="mi">80</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">overflow</span><span class="p">:</span> <span class="kc">hidden</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">border-radius</span><span class="p">:</span> <span class="mi">0</span><span class="kt">px</span><span class="o">/</span><span class="mi">30</span><span class="kt">px</span> <span class="mi">30</span><span class="kt">px</span><span class="o">/</span><span class="mi">30</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">box-shadow</span><span class="p">:</span> <span class="mi">20</span><span class="kt">px</span> <span class="mi">40</span><span class="kt">px</span> <span class="mi">40</span><span class="kt">px</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">transition</span><span class="p">:</span> <span class="k">width</span> <span class="mf">0.5</span><span class="kt">s</span> <span class="kc">ease</span> <span class="mi">0</span><span class="kt">s</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">z-index</span><span class="p">:</span> <span class="mi">999</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">@</span><span class="k">media</span> <span class="nt">screen</span> <span class="nt">and</span> <span class="o">(</span><span class="nt">max-width</span><span class="o">:</span> <span class="nt">768px</span><span class="o">)</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nc">sidebar</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">display</span><span class="p">:</span> <span class="kc">none</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">sidebar</span><span class="p">:</span><span class="nd">hover</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">width</span><span class="p">:</span> <span class="mi">270</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">height</span><span class="p">:</span> <span class="mi">100</span><span class="kt">vh</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>主题中完整的侧边 css 可从 <a href="https://github.com/AikenH/papermod-sidebar/blob/master/assets/css/common/sidebar.css" target="_blank" rel="noopener">sidebar.css at · AikenH/papermod-sidebar</a>
 获取。</p>
<h2 id="extensions-功能拓展">Extensions 功能拓展</h2>
<h3 id="disqus-support-使用-disqus-作为评论区">Disqus Support 使用 Disqus 作为评论区</h3>
<blockquote>
<p>为博客添加评论区实际上有比较多的选择，这里由于之前使用的都是 disqus，这里暂时就不做切换，后续如果有需求的话可能会做别的尝试，例如 <a href="https://tunan.org/posts/add-comment-system-to-hugopapermo/" target="_blank" rel="noopener">giscus</a>
</p>
</blockquote>
<p>参考 PaperMod 主题的说明 <span class="sidenote-number"><small class="sidenote"><a href="https://github.com/adityatelange/hugo-PaperMod/wiki/Features#comments" target="_blank" rel="noopener">papermod-wiki-comments</a></small></span> ，创建 <code>layouts/partials/comments.html</code> ，然后将 disqus 获取的代码贴进去，同时在设置 <code>hugo.yaml</code> 中打开评论区即可。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">params</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">comments</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>而由于 disqus 在国内的访问不是特别的友好，可能会成为页面加载的瓶颈，甚至阻碍其他核心的板块的加载进程，因此使用<strong>延迟加载方案</strong>使得当页面滚动到评论区域时才开始加载 disqus 板块，这里建议去原作者站点查看，故不再赘述  <span class="sidenote-number"><small class="sidenote"><a href="https://blog.skk.moe/post/prevent-disqus-from-slowing-your-site/" target="_blank" rel="noopener">使 Disqus 不再拖累性能和页面加载 | Sukka&rsquo;s Blog</a>
 感谢作者，这也是本博客使用的方案</small></span> <span class="sidenote-number"><small class="sidenote"><a href="https://css-tricks.org.cn/lazy-loading-disqus-comments/" target="_blank" rel="noopener">延迟加载 Disqus 评论 | CSS-Tricks 中文</a>
 感谢作者分享</small></span></p>
<p>此外由于觉得 disqus 的 reactions 模块有点烦人，因此在设置中讲 reactions 板块关闭 <span class="sidenote-number"><small class="sidenote"><a href="https://github.com/disqus/disqus-react/issues/146" target="_blank" rel="noopener">Document how to disable reactions · Issue #146 · disqus/disqus-react</a></small></span> ;</p>
<h3 id="busuanzi-统计网站访问人数">busuanzi 统计网站访问人数</h3>
<p>使用<a href="https://busuanzi.ibruce.info/" target="_blank" rel="noopener">不蒜子</a>
统计站点访问次数和人数，参考官方教程将对应的代码嵌入 footer 中即可，如果需要人次的话就把 pv 改成 uv 。</p>
<p>最终代码如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">...
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">async</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">span</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;busuanzi_container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            Visitors: <span class="p">&lt;</span><span class="nt">span</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;busuanzi_value_site_uv&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            Views: <span class="p">&lt;</span><span class="nt">span</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;busuanzi_value_site_pv&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span> 
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果希望初始化站点的访问量和人数，避免域名转换后的重新计数，可以使用在西面添加 js 脚本对技术进行调整，可以参考 <a href="https://kyxie.me/zh/blog/tech/web/papermod/#%e6%b5%81%e9%87%8f%e7%bb%9f%e8%ae%a1" target="_blank" rel="noopener">Hugo + PaperMod搭建技术博客 | Kunyang&rsquo;s Blog</a>
 这里不再重复说明。</p>
<h3 id="sakana-widget-石蒜模拟器">Sakana Widget 石蒜模拟器</h3>
<p>页面中引入 Sakana 摆件<span class="sidenote-number"><small class="sidenote"><a href="https://github.com/dsrkafuu/sakana-widget?tab=readme-ov-file" target="_blank" rel="noopener">dsrkafuu/sakana-widget: Sakana widget for Web. | 网页小组件版本的石蒜模拟器。</a></small></span>，并将其自定义了欣欣向荣两兄弟的图片效果如下：</p>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
    <script src="https://cdn.jsdmirror.com/npm/jquery@3.3.1/dist/jquery.min.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdmirror.com/npm/nanogallery2@3.0.5/dist/css/nanogallery2.min.css">
    <script src="https://cdn.jsdmirror.com/npm/nanogallery2@3.0.5/dist/jquery.nanogallery2.min.js"></script>
</head>
<body>

<div data-nanogallery2='{
	 "thumbnailDisplayTransition":          "none",
     "thumbnailDisplayTransitionDuration":  500,
     "thumbnailDisplayInterval":            30,
     "galleryDisplayTransition":            "none",
     "galleryDisplayTransitionDuration":    500,
     "galleryDisplayMode": "rows",
     "thumbnailDisplayOutsideScreen": "false",
     "eventsDebounceDelay": 10,
     "thumbnailL1BorderHorizontal": 0,
     "thumbnailL1BorderVertical": 0,
     "thumbnailLabel": {
        "titleFontSize": "0.6em"
     },
     "thumbnailHoverEffect2": "image_scale_1.00_1.10|label_backgroundColor_rgba(0,0,0,0)_rgba(255,255,255,0)",
     "galleryTheme": {
        "thumbnail": {
            "borderRadius": "8px"
        }
     },
     "thumbnailToolbarImage": {
        "topLeft": "",
        "topRight": "",
        "bottomLeft": "",
        "bottomRight": ""
     },
     "viewerToolbar":   {
        "display": true,
        "standard": "label"
     },
     "viewerTools":     {
        "topLeft":    "pageCounter, playPauseButton",
        "topRight":   "downloadButton, rotateLeft, zoomButton, fullscreenButton, closeButton"
     },
     "viewerGalleryTWidth": 40,
     "viewerGalleryTHeight": 40
}'>
     
<a href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241220115346.png" data-ngThumb="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241220115346.png">欣欣</a>
<a href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241220115403.png" data-ngThumb="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241220115403.png">小荣</a>

</div>
</body>
</html>
<p>该组件的使用，包括样式的调整文档里已经非常详细了，这里不在多说；</p>
<blockquote>
<p>以供参考：本文在 hugo 中引入相关代码的位置位于<code>layouts/partials/header,html</code>的末尾</p>
</blockquote>
<p>本文引入新角色的代码如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">initSakanaWidget</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="kr">const</span> <span class="nx">ronSang</span> <span class="o">=</span> <span class="nx">SakanaWidget</span><span class="p">.</span><span class="nx">getCharacter</span><span class="p">(</span><span class="s1">&#39;chisato&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="nx">ronSang</span><span class="p">.</span><span class="nx">initialState</span> <span class="o">=</span> <span class="p">{</span> 
</span></span><span class="line"><span class="cl">		<span class="p">...</span><span class="nx">ronSang</span><span class="p">.</span><span class="nx">initialState</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">controls</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">t</span><span class="o">:</span> <span class="mf">0.8</span><span class="p">,</span> <span class="nx">i</span><span class="o">:</span> <span class="mf">0.002</span><span class="p">,</span> <span class="nx">s</span><span class="o">:</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">d</span><span class="o">:</span> <span class="mf">0.999</span><span class="p">,</span> <span class="nx">t</span><span class="o">:</span> <span class="mf">0.5</span><span class="p">,</span> <span class="nx">w</span><span class="o">:</span> <span class="mf">0.05</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">ronSang</span><span class="p">.</span><span class="nx">image</span> <span class="o">=</span> <span class="s1">&#39;xxx.png&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="nx">SakanaWidget</span><span class="p">.</span><span class="nx">registerCharacter</span><span class="p">(</span><span class="s1">&#39;ronSang&#39;</span><span class="p">,</span> <span class="nx">ronSang</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="k">new</span> <span class="nx">SakanaWidget</span><span class="p">({</span> <span class="nx">character</span><span class="o">:</span> <span class="s1">&#39;ronSang&#39;</span> <span class="p">}).</span><span class="nx">mount</span><span class="p">(</span><span class="s1">&#39;#sakana-widget&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">...</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="world-cloud-词云">World Cloud 词云</h3>
<p>尝试了一下做标签云，试图优化一下 tag 页面，但是设置了背景以后配合的不是很好，因此本博客中没有使用这个功能，这里分享一下实现词云 <span class="sidenote-number"><small class="sidenote"><a href="https://blog.xlap.top/post/tech/wordcloud4hugo/" target="_blank" rel="noopener">Hugo的标签使用词云WordCloud2展示 | Blog - XLapTop</a></small></span> <span class="sidenote-number"><small class="sidenote"><a href="https://github.com/timdream/wordcloud2.js/blob/gh-pages/API.md" target="_blank" rel="noopener">wordcloud2.js/API.md at gh-pages · timdream/wordcloud2.js</a></small></span> <span class="sidenote-number"><small class="sidenote"><a href="https://blog.cubieserver.de/2020/adding-a-tag-cloud-to-my-hugo-blog/" target="_blank" rel="noopener">Adding a Tag Cloud to my Hugo blog · Jack Henschel&rsquo;s Blog</a></small></span> 的代码:</p>
<p>这里需要去 <a href="https://github.com/timdream/wordcloud2.js/blob/gh-pages/src/wordcloud2.js" target="_blank" rel="noopener">wordcloud2.js/src/wordcloud2.js at gh-pages · timdream/wordcloud2.js</a>
 将该 js 文件存在 static 目录下，然后将下述代码替换到 <code>layouts/_default/terms.html</code> 中</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="c">&lt;!--标签云--&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;sourrounding_div&#34;</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;width:100%;height:100%;min-height: 500px;&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;tag-canvas&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;/js/wordcloud2.js&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">{{- range $key, $value := .Data.Terms.Alphabetical }}
</span></span><span class="line"><span class="cl">    {{ if eq &#34;&#34; ($.Scratch.Get &#34;tagsMap&#34;) }}
</span></span><span class="line"><span class="cl">        {{ $.Scratch.Set &#34;tagsMap&#34; (slice (dict .Name .Count))  }}
</span></span><span class="line"><span class="cl">    {{ else }}
</span></span><span class="line"><span class="cl">        {{ $.Scratch.Add &#34;tagsMap&#34; (slice (dict .Name .Count)) }}
</span></span><span class="line"><span class="cl">    {{ end }}
</span></span><span class="line"><span class="cl">{{- end }}
</span></span><span class="line"><span class="cl">{{ $result := ($.Scratch.Get &#34;tagsMap&#34;)}}
</span></span><span class="line"><span class="cl">`<span class="p">&lt;</span><span class="nt">span</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;tag-temp&#34;</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;display:none&#34;</span><span class="p">&gt;</span>`{{$result | jsonify }}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="c1">//因为前期每个标签值比较小，帮X一个系数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">//为了动态宽度[[]()]()
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kd">var</span> <span class="nx">div</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;#sourrounding_div&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nx">canvas</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;#tag-canvas&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">canvas</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">width</span> <span class="o">=</span> <span class="nx">div</span><span class="p">.</span><span class="nx">offsetWidth</span><span class="o">+</span><span class="s1">&#39;px&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">canvas</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">height</span> <span class="o">=</span> <span class="nx">div</span><span class="p">.</span><span class="nx">offsetHeight</span><span class="o">+</span><span class="s1">&#39;px&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nx">wordFreqData</span> <span class="o">=</span>  <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;#tag-temp&#34;</span><span class="p">).</span><span class="nx">innerHTML</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">tagMap</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Map</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">tagArray</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Array</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">{{</span><span class="o">-</span> <span class="nx">range</span> <span class="nx">$key</span><span class="p">,</span> <span class="nx">$value</span> <span class="o">:=</span> <span class="p">.</span><span class="nx">Data</span><span class="p">.</span><span class="nx">Terms</span> <span class="p">}}</span>
</span></span><span class="line"><span class="cl">    <span class="nx">tagMap</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s2">&#34;{{ $key }}&#34;</span><span class="p">,</span> <span class="p">{{</span><span class="o">-</span> <span class="nx">len</span> <span class="nx">$value</span> <span class="p">}});</span>
</span></span><span class="line"><span class="cl">    <span class="nx">tagArray</span><span class="p">.</span><span class="nx">push</span><span class="p">([{{</span><span class="o">-</span> <span class="nx">$key</span> <span class="p">}},</span> <span class="p">{{</span><span class="o">-</span> <span class="nx">len</span> <span class="nx">$value</span> <span class="p">}}]);</span>
</span></span><span class="line"><span class="cl">    <span class="p">{{</span><span class="o">-</span> <span class="nx">end</span> <span class="p">}}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1">//获取当前是暗色还是浅色
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kd">var</span> <span class="nx">isDark</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">className</span><span class="p">.</span><span class="nx">includes</span><span class="p">(</span><span class="s2">&#34;dark&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">WordCloud</span><span class="p">(</span><span class="nx">canvas</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="s2">&#34;list&#34;</span><span class="o">:</span> <span class="nx">tagArray</span><span class="p">,</span><span class="c1">//或者[[&#39;各位观众&#39;,45],[&#39;词云&#39;, 21],[&#39;来啦!!!&#39;,13]],只要格式满足这样都可以
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>          <span class="s2">&#34;shape&#34;</span><span class="o">:</span> <span class="s2">&#34;diamond&#34;</span><span class="p">,</span> <span class="c1">//形状 circle (default), cardioid (心型), diamond, square, triangle-forward, triangle, pentagon, and star.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>          <span class="s2">&#34;gridSize&#34;</span><span class="o">:</span> <span class="mi">18</span><span class="p">,</span> <span class="c1">// 密集程度 数字越小越密集
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>          <span class="s2">&#34;weightFactor&#34;</span><span class="o">:</span> <span class="mi">6</span><span class="p">,</span> <span class="c1">// 字体大小=原始大小*weightFactor
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>          <span class="s2">&#34;fontWeight&#34;</span><span class="o">:</span> <span class="s1">&#39;normal&#39;</span><span class="p">,</span> <span class="c1">//字体粗细
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>          <span class="s2">&#34;fontFamily&#34;</span><span class="o">:</span> <span class="s1">&#39;Times, serif&#39;</span><span class="p">,</span> <span class="c1">// 字体
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>          <span class="s2">&#34;hover&#34;</span><span class="o">:</span> <span class="nb">window</span><span class="p">.</span><span class="nx">drawBox</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="s2">&#34;color&#34;</span><span class="o">:</span> <span class="nx">isDark</span><span class="o">?</span><span class="s1">&#39;random-light&#39;</span><span class="o">:</span><span class="s1">&#39;random-dark&#39;</span><span class="p">,</span> <span class="c1">// 字体颜色 &#39;random-dark&#39; 或者 &#39;random-light&#39;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>          <span class="s2">&#34;backgroundColor&#34;</span><span class="o">:</span> <span class="s1">&#39;transparent&#39;</span><span class="p">,</span> <span class="c1">// 背景颜色
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>          <span class="s2">&#34;classes&#34;</span><span class="o">:</span> <span class="s2">&#34;tag-cloud-item word-color&#34;</span><span class="p">,</span> <span class="c1">//用于点击事件
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>          <span class="s2">&#34;shrinkToFit&#34;</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="s2">&#34;rotationSteps&#34;</span><span class="o">:</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="s2">&#34;minSize&#34;</span><span class="o">:</span> <span class="s2">&#34;32&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="s2">&#34;rotateRatio&#34;</span><span class="o">:</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="p">});</span>
</span></span><span class="line"><span class="cl">      <span class="nx">canvas</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;wordcloudstop&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">//点击
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="nb">document</span><span class="p">.</span><span class="nx">querySelectorAll</span><span class="p">(</span><span class="s1">&#39;.tag-cloud-item&#39;</span><span class="p">).</span><span class="nx">forEach</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">element</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="kr">const</span> <span class="nx">text</span> <span class="o">=</span> <span class="nx">element</span><span class="p">.</span><span class="nx">innerHTML</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="nx">element</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="sb">`&lt;a href=&#34;https://aikenh.cn/tags/</span><span class="si">${</span><span class="nx">text</span><span class="si">}</span><span class="sb">&#34; style=&#34;color: inherit;&#34;&gt;</span><span class="si">${</span><span class="nx">text</span><span class="si">}</span><span class="sb">&lt;/a&gt;`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="p">});</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">{{- end }}{{/* end main */ -}}</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>效果演示如下，各种的形状，参数等可以根据官网进行调整尝试，找到适合自己的。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241220104910.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241220104910.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241220104910.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="gallery-使用简码支持-neogallery2">gallery 使用简码支持 neogallery2</h3>
<p>参考：<a href="https://cloud.tencent.com/developer/article/2246324" target="_blank" rel="noopener">Hugo博客添加相册功能-腾讯云-素履coder</a>
 的实现，这里不赘述，感谢博主，可以参照下一个章节优化一下国内的速度，替换一下 CDN。</p>
<h2 id="cdn-加速访问">CDN 加速访问</h2>
<p>通过 CDN <span class="sidenote-number"><small class="sidenote">Content Delivery Network 内容分发网络，使用靠近访问者的服务器为其分发内容</small></span> 来加速博客在不同地区的访问速度；</p>
<p>国内目前可用的 CDN 节点的话可以参考 <a href="https://blog.akass.cn/resources/mirrors" target="_blank" rel="noopener">aksBlog</a>
，感谢其整理与分享，目前本站主要使用的是cdn.jsdmirror.com <span class="sidenote-number"><small class="sidenote">感谢 blog.jsdmirror.com</small></span> ;</p>
<p>此外其实也可以将一些资源直接上传至仓库，直接利用发布平台托管静态文件，利用托管平台自身的服务也行吧；</p>
<h2 id="something-more">Something More</h2>
<h3 id="一些注意事项">一些注意事项</h3>
<p><strong>调试的时候</strong>记得使用 <code>--cleanDestinationDir</code> 选项，不然有时部分页面生成失败了，延续了之前的页面，会使得定位错误变得更加复杂麻烦。</p>
<h3 id="一些其他博主的设计">一些其他博主的设计</h3>
<ul>
<li><a href="https://loyayz.com/website/220610-hugo-papermodx-series-in-search-page.md/" target="_blank" rel="noopener">PaperMod 搜索页展示系列列表 | loyayz</a>
</li>
<li><a href="https://sspai.com/post/87431" target="_blank" rel="noopener">我的Hugo博客搭建记录 - 少数派</a>
 最后两个章节，集成 loading 和 memos =》 <a href="https://morick66.com/post/20241111200044/" target="_blank" rel="noopener">Obsidian到Anytype：Anytype介绍+个人实践分享</a>
 有很多有意思的页面爆改</li>
<li><a href="https://kenshin2438.top/archives/a8baf211.html/" target="_blank" rel="noopener">Hello World - Hugo博客搭建笔记 | Kenshin2438</a>
 一些修改的点子，虽然有一些没有实现</li>
<li><a href="https://hermygong.com/posts/papermod/build-my-website/#%e5%88%9b%e5%bb%ba%e7%ab%99%e7%82%b9%e5%92%8c%e4%b8%bb%e9%a2%98" target="_blank" rel="noopener">零基础搭建我的个人博客 | HermyGong&rsquo;s Studio</a>
 简单入门</li>
<li><a href="https://kdjlyy.github.io/posts/tech/markdown-note/#fnref:1" target="_blank" rel="noopener">PaperMod主题Markdown示例 | 向着悠远的苍穹</a>
</li>
</ul>
<h2 id="fi-写在最后">Fi 写在最后</h2>
<p>本博客的源码位于：<a href="https://github.com/AikenH/hugoblog" target="_blank" rel="noopener">AikenH/hugoblog: my blog’s hugo variant.</a>
 with submodule <a href="https://github.com/AikenH/papermod-sidebar" target="_blank" rel="noopener">AikenH/papermod-sidebar: my sidebar &amp; transparnet background variant of papermod</a>
</p>
<p>一些处理脚本后续可能会分享到：<a href="https://github.com/AikenH/ManipulateMarkdownNotes" target="_blank" rel="noopener">AikenH/ManipulateMarkdownNotes: manipulate markdown file for publish or some other reason</a>
 目前在 dev 分支完善中。</p>
<p>文中有任何错误、版权使用不当之处、或者问题欢迎指正和交流，可以留言也可以发邮件；</p>
]]></content:encoded>
    </item>
    <item>
      <title>初始化&amp;设置PaperMod主题的基础功能</title>
      <link>https://aikenh.cn/posts/%E5%88%9D%E5%A7%8B%E5%8C%96%E8%AE%BE%E7%BD%AEpapermod%E4%B8%BB%E9%A2%98%E7%9A%84%E5%9F%BA%E7%A1%80%E5%8A%9F%E8%83%BD/</link>
      <pubDate>Thu, 12 Dec 2024 13:26:12 +0000</pubDate>
      <guid>https://aikenh.cn/posts/%E5%88%9D%E5%A7%8B%E5%8C%96%E8%AE%BE%E7%BD%AEpapermod%E4%B8%BB%E9%A2%98%E7%9A%84%E5%9F%BA%E7%A1%80%E5%8A%9F%E8%83%BD/</guid>
      <description>以PaperMod主题为例，初始化hugo主题，并配置一些基础的功能</description>
      <content:encoded><![CDATA[<p>本文其实是配置和自定义 hugo 主题的第一章，从 papermod 的部署开始，记录整个基于 papermod 进行功能拓展和定制化的过程；</p>
<h2 id="setup-papermod-安装和设置-papermod">Setup PaperMod 安装和设置 PaperMod</h2>
<h3 id="init-hugo-project-初始化-hugo-项目">Init Hugo Project 初始化 Hugo 项目</h3>
<p>通过 hugo 指令新建一个 hugo 项目并制定使用 yaml 格式的配置进行设置；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">hugo new site <span class="o">{</span>your-proj-name<span class="o">}</span> --format yaml</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>进入目录并通过 <code>git clone</code> 安装一个主题到 theme/ 目录下，如果想要使用 git 进行一些版本管理进行自己的修改，可能需要使用 submodule 的方式添加；</p>
<p>如果想直接对主题的内容也进行修改的话，建议先 fork 一下原仓库，将 fork 的仓库作为 submodule 和 hugo proj 一起进行版本管理和开发；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nb">cd</span> <span class="o">{</span>your-proj-name<span class="o">}</span>
</span></span><span class="line"><span class="cl">git init <span class="c1"># [optional] for develop</span>
</span></span><span class="line"><span class="cl">git clone https://github.com/adityatelange/hugo-PaperMod themes/PaperMod --depth<span class="o">=</span><span class="m">1</span> 
</span></span><span class="line"><span class="cl">git submodule add --depth<span class="o">=</span><span class="m">1</span> https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod <span class="c1"># [optional] for develop</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果是自己的仓库，记得使用 git 的方式拉取，如果用 http 的方式拉取后，可能无法提交后续的修改，可以用下列命令去修改 submodule 对应的 url <span class="sidenote-number"><small class="sidenote"><a href="https://stackoverflow.com/questions/913701/how-to-change-the-remote-repository-for-a-git-submodule" target="_blank" rel="noopener">How to change the remote repository for a git submodule? - Stack Overflow</a></small></span></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git submodule set-url themes/PaperMod git@github.com:<span class="o">{</span>your-proj<span class="o">}</span>.git</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><blockquote>
<p>后续部署的分支需要转换为 http 的形式，这里可以参见后面部署的文章。</p>
</blockquote>
<h3 id="manage-your-configurations-配置文件管理">Manage Your Configurations 配置文件管理</h3>
<p>推荐使用 config 文件夹切分基础配置和主题配置，这样方便在多个主题之间进行切换；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">cd</span> your-prj-name
</span></span><span class="line"><span class="cl">mkdir -p config/_default
</span></span><span class="line"><span class="cl">mkdir -p config/papermod
</span></span><span class="line"><span class="cl">touch config/paermod/hugo.yaml</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>配置文件相关的目录结构如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">.
</span></span><span class="line"><span class="cl">├── hugo.yaml
</span></span><span class="line"><span class="cl">├── config
</span></span><span class="line"><span class="cl">│   ├── _default
</span></span><span class="line"><span class="cl">│   │   └── hugo.yaml
</span></span><span class="line"><span class="cl">│   └── papermod
</span></span><span class="line"><span class="cl">│       └── hugo.yaml</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>此处使用根目录的 <code>hugo.yaml</code> 作为默认的配置文件，<code>papermod/hugo.yaml</code> 设置主题特有的配置项，启动特定主题时使用 <code>--environment {config-dif}</code> 指定使用特定的配置文件：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">hugo --environment papermod server</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><blockquote>
<p>该部分具体的配置切分目前还没有完全确定，暂时还没有深入尝试使用别的主题，但是结构上应该是没问题的；</p>
</blockquote>
<h3 id="hugos-organization-博客的文件夹组织逻辑">Hugo&rsquo;s Organization 博客的文件夹组织逻辑</h3>
<p>在进行后续的修改和迭代之前，了解一下 hugo 目录结构对应的作用 <span class="sidenote-number"><small class="sidenote"><a href="https://hugo.opendocs.io/getting-started/directory-structure/" target="_blank" rel="noopener">目录结构 | Hugo官方文档</a></small></span> 是相当重要的，此外由于本文对 PaperMod 主题进行修改，也要对 PaperMod 的覆盖逻辑有一定的了解，包括模版覆盖 <span class="sidenote-number"><small class="sidenote"><a href="https://github.com/adityatelange/hugo-PaperMod/wiki/FAQs#override-theme-template" target="_blank" rel="noopener">hugo-PaperMod Wiki-override-theme-template</a></small></span> 和样式覆盖 <span class="sidenote-number"><small class="sidenote"><a href="https://github.com/adityatelange/hugo-PaperMod/wiki/FAQs#bundling-custom-css-with-themes-assets" target="_blank" rel="noopener">hugo-PaperMod Wiki-bundling-custom-css-with-themes-assets</a></small></span> ，由于官方文档中的介绍都比较详细，这里就不在赘述。</p>
<p>这里有一个特殊功能界面 <code>_index.md</code> 可以通过<a href="https://hugo.opendocs.io/content-management/organization/" target="_blank" rel="noopener">内容组织 | Hugo官方文档</a>
 简单了解并尝试一下，后面对组织文档和界面可能会有用武之地。</p>
<h3 id="papermod-setting-主题的基础页面配置">PaperMod Setting 主题的基础页面配置</h3>
<p><strong>一、设置自己的文章模版</strong></p>
<p>Archetypes 文件夹中可以注册不同的文章模版 <code>archetypes/{template.md}</code>，可以使用下列命令来基于指定的模版新建文章，此处由于大多时候都是直接使用 obsidian 编写后迁移过来的，该部分就不做太多说明；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">hugo new --kind template <span class="o">{</span>post-name<span class="o">}</span>.md</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>但是<a href="https://github.com/adityatelange/hugo-PaperMod/wiki/Installation#sample-pagemd" target="_blank" rel="noopener">官方模版中页面</a>
包含了大量的元数据信息，如果不是需要经常修改的属性，可以直接丢到 <code>Theme/Hugo.yaml</code> 中，避免每个 markdown 的元信息都十分冗长，等需要修改的时候再用指定的 <code>markdown</code> 上新增去覆盖即可；</p>
<p><strong>二、启用 Archive 、 Search 、About页面等</strong></p>
<p>此外 PaperMod 的很多页面是没有默认开启的包括 Search，Archive ，这些参考<a href="https://github.com/adityatelange/hugo-PaperMod/wiki/Features" target="_blank" rel="noopener">官方 wiki</a>
 或者中文的话 <a href="https://www.shaohanyun.top/posts/env/blog_build2/" target="_blank" rel="noopener">PaperMod主题配置 | 🚀 田少晗的个人博客</a>
 简单配置一下这些页面，并启动 server 看一下这些页面是否正常生成；</p>
<p>about 界面可以仿照 archive 界面直接创建一个 about.md 在 content 目录中，最终其呈现的 URL 如下：<code>http://localhost:1313/about/</code>，content 中存放文件的最终路径均类似，会包含对应的文件夹路径。创建完成后将其新增到导航栏中 <span class="sidenote-number"><small class="sidenote"><a href="https://github.com/adityatelange/hugo-PaperMod/wiki/FAQs#add-menu-to-site" target="_blank" rel="noopener">FAQs · adityatelange/hugo-PaperMod Wiki</a></small></span> :</p>
<p><strong>三、参考<a href="https://github.com/adityatelange/hugo-PaperMod/wiki/Features" target="_blank" rel="noopener">官方wiki</a>
 完成自己需要的基本模式和参数设置。</strong></p>
<p>完成上面三步设置之后，添加一下博文测试一下各方面效果是否符合预期，没问题的话就可以开始折腾了👹</p>
<h2 id="extra-basic-function-support-额外基础功能支持">Extra Basic Function Support 额外基础功能支持</h2>
<p>现在编写 Markdown 的时候事实上大多都额外支持或者使用了 Html 的部分语法来使得 Markdown 更加美观，或者是 Latex 来记录一些数学推导，但是博客本身这些功能要么没有默认开启或者是没有很好的支持，因此首先拓展这些基础功能；</p>
<h3 id="render-html-支持对-html-的渲染">Render Html 支持对 html 的渲染</h3>
<p>基于安全性考虑，默认的 Goldmark 并不会渲染混合在 markdown 中的 html <span class="sidenote-number"><small class="sidenote"><a href="https://gohugo.io/getting-started/configuration-markup/#rendererunsafe" target="_blank" rel="noopener">Configure markup | Hugo</a></small></span> ，要打开的话修改/添加如下设置即可：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">markup</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">goldmark</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">renderer</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">unsafe</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><blockquote>
<p>这里请确保自己的 html 内容是安全的</p>
</blockquote>
<h3 id="render-latex-支持渲染-latex">Render Latex 支持渲染 Latex</h3>
<p>这一部分相关的资料和文章还是比较多的，主要会遇到的问题都是由于 markdown 渲染和 latex 渲染之间的冲突导致的，被 <code> $</code> 或者 <code>$$ </code> 包裹的内容需要如何被匹配和被谁渲染，以及一些其他的特殊字符之间的问题；</p>



  
  

<blockquote class="alert-blockquote alert-error">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Error</span>
  </p>
  <p>没有特别处理过的话，最终会导致一些复杂的 Latex 或者是一些内联公式导致最后的样式混乱；</p>

</blockquote>
<p>经过多种尝试后，这里最终使用的如下方案 <span class="sidenote-number"><small class="sidenote">使用 <a href="https://gohugo.io/content-management/mathematics/" target="_blank" rel="noopener">Mathematics in Markdown | Hugo</a>
 中的分隔符处理</small></span> <span class="sidenote-number"><small class="sidenote">使用 <a href="https://kiwamizamurai.github.io/posts/2022-03-06/" target="_blank" rel="noopener">How to enable latex on PaperMod | terakoya</a>
 该博主的 katex 方案</small></span>  <span class="sidenote-number"><small class="sidenote"><a href="https://github.com/adityatelange/hugo-PaperMod/issues/236" target="_blank" rel="noopener">How to enable Math Typesetting in PaperMod? · Issue #236 · adityatelange/hugo-PaperMod</a>
 也提到了这种混合解法</small></span> ：</p>
<p>修改 <code>hugo.yaml</code> ：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">markup</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">goldmark</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">extensions</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">passthrough</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">delimiters</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">block</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span>- - <span class="l">\[</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span>- <span class="l">\]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span>- - <span class="l">$$</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span>- <span class="l">$$</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">inline</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span>- - <span class="l">\(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span>- <span class="l">\)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">enable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">params</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">math</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在 <code>layouts/partials</code> 中添加 <code>math.html</code></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css&#34;</span> <span class="na">integrity</span><span class="o">=</span><span class="s">&#34;sha384-MlJdn/WNKDGXveldHDdyRP1R4CTHr3FeuDNfhsLPYrq2t0UBkUdK2jyTnXPEK1NQ&#34;</span> <span class="na">crossorigin</span><span class="o">=</span><span class="s">&#34;anonymous&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c">&lt;!-- The loading of KaTeX is deferred to speed up page rendering --&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">defer</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.js&#34;</span> <span class="na">integrity</span><span class="o">=</span><span class="s">&#34;sha384-VQ8d8WVFw0yHhCk5E8I86oOhv48xLpnDZx5T9GogA/Y84DcCKWXDmSDfn13bzFZY&#34;</span> <span class="na">crossorigin</span><span class="o">=</span><span class="s">&#34;anonymous&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c">&lt;!-- To automatically render math in text elements, include the auto-render extension: --&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">defer</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/contrib/auto-render.min.js&#34;</span> <span class="na">integrity</span><span class="o">=</span><span class="s">&#34;sha384-+XBljXPPiv+OzfbB3cVmLHf4hdUFHlWNZN5spNQ7rmHTXpd7WvJum6fIACpNNfIR&#34;</span> <span class="na">crossorigin</span><span class="o">=</span><span class="s">&#34;anonymous&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">onload</span><span class="o">=</span><span class="s">&#34;renderMathInElement(document.body);&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c">&lt;!-- for inline --&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nb">document</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;DOMContentLoaded&#34;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">renderMathInElement</span><span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">delimiters</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span><span class="nx">left</span><span class="o">:</span> <span class="s2">&#34;$$&#34;</span><span class="p">,</span> <span class="nx">right</span><span class="o">:</span> <span class="s2">&#34;$$&#34;</span><span class="p">,</span> <span class="nx">display</span><span class="o">:</span> <span class="kc">true</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span><span class="nx">left</span><span class="o">:</span> <span class="s2">&#34;$&#34;</span><span class="p">,</span> <span class="nx">right</span><span class="o">:</span> <span class="s2">&#34;$&#34;</span><span class="p">,</span> <span class="nx">display</span><span class="o">:</span> <span class="kc">false</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在 <code>layouts/partials/extend_head.html</code> 的末尾添加如下内容：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">{{ if or .Params.math .Site.Params.math }}
</span></span><span class="line"><span class="cl">{{ partial &#34;math.html&#34; . }}
</span></span><span class="line"><span class="cl">{{ end }}</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>此外，针对有时因为三个 <code>{{{</code> 的出现导致渲染公式异常的情况<span class="sidenote-number"><small class="sidenote"><a href="https://www.shaohanyun.top/posts/env/hugo_mathjax/" target="_blank" rel="noopener">Hugo博客添加LaTeX语法支持 | 🚀 田少晗的个人博客</a></small></span>，可以通过脚本在 publish 时在代码块外侧添加 <code>&lt;div&gt;&lt;/div&gt;</code> 避免 markdown 干涉公式的渲染，使其正确渲染：</p>
<p>这里提供我的处理脚本，以供参考：</p>
<blockquote>
<p>并不一定需要处理，可以视自己配置后的具体情况而定</p>
</blockquote>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">_surround_latex_by_tag</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">content</span><span class="p">:</span><span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># *. need to match those inline latex &amp; block latex &amp; ignore those $ in ``` block</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 1. read code block and ignore it.</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 非贪婪匹配</span>
</span></span><span class="line"><span class="cl">        <span class="n">code_block_pattern</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s1">&#39;```.*?```&#39;</span><span class="p">,</span> <span class="n">re</span><span class="o">.</span><span class="n">DOTALL</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">preserved_code_blocks</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="k">match</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">code_block_pattern</span><span class="o">.</span><span class="n">finditer</span><span class="p">(</span><span class="n">content</span><span class="p">)):</span>
</span></span><span class="line"><span class="cl">            <span class="n">placeholder</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&#34;__CODE_BLOCK_</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">__&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="n">preserved_code_blocks</span><span class="p">[</span><span class="n">placeholder</span><span class="p">]</span> <span class="o">=</span> <span class="k">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">content</span> <span class="o">=</span> <span class="n">content</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="k">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span> <span class="n">placeholder</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># 2. add space surround the inline latex sentence</span>
</span></span><span class="line"><span class="cl">        <span class="n">inline_latex_pattern</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s1">&#39;(?&lt;!\ $)(\$ .*?\ $)(?!\$ )&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="n">content</span> <span class="o">=</span> <span class="n">inline_latex_pattern</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="k">lambda</span> <span class="k">match</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_latex_add_space_inline</span><span class="p">(</span><span class="k">match</span><span class="p">,</span> <span class="n">content</span><span class="p">),</span> <span class="n">content</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># 3. add newline between the `\ $\$ ` block or `\ $\$ \$` block </span>
</span></span><span class="line"><span class="cl">        <span class="n">block_latex_pattern</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s1">&#39;(?&lt;!\S)(\ $\$ .*?\ $\$ |(?&lt;!\S)\ $\$ \ $.*?\$ \ $\$ )(?!\S)&#39;</span><span class="p">,</span> <span class="n">re</span><span class="o">.</span><span class="n">DOTALL</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">content</span> <span class="o">=</span> <span class="n">block_latex_pattern</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="k">lambda</span> <span class="k">match</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_latex_add_div_tags</span><span class="p">(</span><span class="k">match</span><span class="p">,</span> <span class="n">content</span><span class="p">),</span> <span class="n">content</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># 4. restore the code block</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">placeholder</span><span class="p">,</span> <span class="n">code_block</span> <span class="ow">in</span> <span class="n">preserved_code_blocks</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">            <span class="n">content</span> <span class="o">=</span> <span class="n">content</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">placeholder</span><span class="p">,</span> <span class="n">code_block</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">content</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>其他参考资料 <span class="sidenote-number"><small class="sidenote"><a href="https://adityatelange.github.io/hugo-PaperMod/posts/math-typesetting/" target="_blank" rel="noopener">Math Typesetting | PaperMod</a></small></span></p>
<h3 id="rss-setting-for-follow-为-follow-认证设置-rss">Rss Setting for Follow 为 follow 认证设置 rss</h3>
<p>Ref： <a href="https://rokcso.com/p/follow-claim-feed/" target="_blank" rel="noopener">Follow 中如何 Claim 自己的博客 | Rokcso&rsquo;s blog</a>
</p>
<p>参考上述文章，在 <code>rss.xml</code> 中设置相关的 RSS Tag 即可，感谢博主的分享；</p>
<h3 id="copyright-setting-在-footer-设置-license">CopyRight Setting 在 footer 设置 License</h3>
<p>参考：<a href="https://www.yunyitang.me/hugo-papermod-blog/" target="_blank" rel="noopener">Hugo+PaperMod 双语博客搭建 Home-Info+Profile Mode - YUNYI BLOG</a>
 ，从 <a href="https://chooser-beta.creativecommons.org/" target="_blank" rel="noopener">Choose a License</a>
 按自己的需求选择一个协议，并设置自己的知识共享协议；</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241218212740.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241218212740.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241218212740.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>我这里直接硬编码进 <code>layouts/partials/footer.html</code> 中 如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">footer</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;footer&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    {{- if not site.Params.footer.hideCopyright }}
</span></span><span class="line"><span class="cl">        {{- if site.Copyright }}
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">span</span><span class="p">&gt;</span>{{ site.Copyright | markdownify }}<span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        {{- else }}
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">span</span><span class="p">&gt;</span><span class="ni">&amp;copy;</span> {{ now.Year }} <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;{{ &#34;</span><span class="err">&#34;</span> <span class="err">|</span> <span class="na">absLangURL</span> <span class="err">}}&#34;</span><span class="p">&gt;</span>{{ site.Title }}<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">span</span> <span class="na">xmlns:cc</span><span class="o">=</span><span class="s">&#34;http://creativecommons.org/ns#&#34;</span> <span class="na">xmlns:dct</span><span class="o">=</span><span class="s">&#34;http://purl.org/dc/terms/&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            Licensed under
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">a</span>
</span></span><span class="line"><span class="cl">              <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://creativecommons.org/licenses/by-nc/4.0/?ref=chooser-v1&#34;</span>
</span></span><span class="line"><span class="cl">              <span class="na">target</span><span class="o">=</span><span class="s">&#34;_blank&#34;</span>
</span></span><span class="line"><span class="cl">              <span class="na">rel</span><span class="o">=</span><span class="s">&#34;license noopener noreferrer&#34;</span>
</span></span><span class="line"><span class="cl">              <span class="na">style</span><span class="o">=</span><span class="s">&#34;display:inline-block;&#34;</span>
</span></span><span class="line"><span class="cl">              <span class="p">&gt;</span>CC BY-NC 4.0 <span class="p">&lt;/</span><span class="nt">a</span>
</span></span><span class="line"><span class="cl">            <span class="p">&gt;&lt;/</span><span class="nt">span</span>
</span></span><span class="line"><span class="cl">        <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        {{- end }}
</span></span><span class="line"><span class="cl">        {{- print &#34; · &#34;}}
</span></span><span class="line"><span class="cl">    {{- end }}</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="basic-style-change-基础样式修改">Basic Style Change 基础样式修改</h2>
<p>PaperMod 主题本身有一些基础样式个人不是很喜欢，例如内容部分的宽度比较窄，在全屏或者宽屏观看的时候比较变扭。因此这里也会针对主题的一些基础样式做针对的调整。</p>
<h3 id="get-wider-space-for-content-拓宽正文区域">Get Wider Space for Content 拓宽正文区域</h3>
<p>根据自己的布局修改 <code>css</code> 中如下属性即可 <span class="sidenote-number"><small class="sidenote"><a href="https://github.com/adityatelange/hugo-PaperMod/discussions/442" target="_blank" rel="noopener">Change width of the content  hugo-PaperMod · Discussion #442</a></small></span> ：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">:</span><span class="nd">root</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--post-width</span><span class="p">:</span> <span class="nf">max</span><span class="p">(</span><span class="mi">60</span><span class="kt">vw</span><span class="p">,</span> <span class="mi">100</span><span class="kt">vh</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--main-width</span><span class="p">:</span> <span class="nf">max</span><span class="p">(</span><span class="mi">60</span><span class="kt">vw</span><span class="p">,</span> <span class="mi">100</span><span class="kt">vh</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="header-counter-为-title-添加章节序号">Header Counter 为 Title 添加章节序号</h3>
<p>直接利用 CSS 的 <code>counter</code> 和 <code>before</code> 属性为正文中的小标题添加对应的章节序号，实现如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">main</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">counter-reset</span><span class="p">:</span> <span class="n">h1-cnt</span> <span class="n">h2-cnt</span> <span class="n">h3-cnt</span> <span class="n">h4-cnt</span> <span class="n">h5-cnt</span> <span class="n">h6-cnt</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</span> <span class="nt">h1</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">counter-increment</span><span class="p">:</span> <span class="n">h1-cnt</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">counter-reset</span><span class="p">:</span> <span class="n">h2-cnt</span> <span class="n">h3-cnt</span> <span class="n">h4-cnt</span> <span class="n">h5-cnt</span> <span class="n">h6-cnt</span><span class="p">;</span> <span class="c">/* Reset lower levels */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</span> <span class="nt">h2</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">counter-increment</span><span class="p">:</span> <span class="n">h2-cnt</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">counter-reset</span><span class="p">:</span> <span class="n">h3-cnt</span> <span class="n">h4-cnt</span> <span class="n">h5-cnt</span> <span class="n">h6-cnt</span><span class="p">;</span> <span class="c">/* Reset lower levels */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</span> <span class="nt">h3</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">counter-increment</span><span class="p">:</span> <span class="n">h3-cnt</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">counter-reset</span><span class="p">:</span> <span class="n">h4-cnt</span> <span class="n">h5-cnt</span> <span class="n">h6-cnt</span><span class="p">;</span> <span class="c">/* Reset lower levels */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</span> <span class="nt">h4</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">counter-increment</span><span class="p">:</span> <span class="n">h4-cnt</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">counter-reset</span><span class="p">:</span> <span class="n">h5-cnt</span> <span class="n">h6-cnt</span><span class="p">;</span> <span class="c">/* Reset lower levels */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</span> <span class="nt">h5</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">counter-increment</span><span class="p">:</span> <span class="n">h5-cnt</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">counter-reset</span><span class="p">:</span> <span class="n">h6-cnt</span><span class="p">;</span> <span class="c">/* Reset lower levels */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</span> <span class="nt">h6</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">counter-increment</span><span class="p">:</span> <span class="n">h6-cnt</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</span> <span class="nt">h1</span><span class="p">::</span><span class="nd">before</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">content</span><span class="p">:</span> <span class="nb">counter</span><span class="p">(</span><span class="n">h1</span><span class="o">-</span><span class="n">cnt</span><span class="p">)</span> <span class="s1">&#39;. &#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</span> <span class="nt">h2</span><span class="p">::</span><span class="nd">before</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">content</span><span class="p">:</span> <span class="nb">counter</span><span class="p">(</span><span class="n">h2</span><span class="o">-</span><span class="n">cnt</span><span class="p">)</span> <span class="s1">&#39;. &#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</span> <span class="nt">h3</span><span class="p">::</span><span class="nd">before</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">content</span><span class="p">:</span> <span class="nb">counter</span><span class="p">(</span><span class="n">h2</span><span class="o">-</span><span class="n">cnt</span><span class="p">)</span> <span class="s1">&#39;.&#39;</span> <span class="nb">counter</span><span class="p">(</span><span class="n">h3</span><span class="o">-</span><span class="n">cnt</span><span class="p">)</span> <span class="s1">&#39;. &#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</span> <span class="nt">h4</span><span class="p">::</span><span class="nd">before</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">content</span><span class="p">:</span> <span class="nb">counter</span><span class="p">(</span><span class="n">h2</span><span class="o">-</span><span class="n">cnt</span><span class="p">)</span> <span class="s1">&#39;.&#39;</span> <span class="nb">counter</span><span class="p">(</span><span class="n">h3</span><span class="o">-</span><span class="n">cnt</span><span class="p">)</span> <span class="s1">&#39;.&#39;</span> <span class="nb">counter</span><span class="p">(</span><span class="n">h4</span><span class="o">-</span><span class="n">cnt</span><span class="p">)</span> <span class="s1">&#39;. &#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</span> <span class="nt">h5</span><span class="p">::</span><span class="nd">before</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">content</span><span class="p">:</span> <span class="nb">counter</span><span class="p">(</span><span class="n">h2</span><span class="o">-</span><span class="n">cnt</span><span class="p">)</span> <span class="s1">&#39;.&#39;</span> <span class="nb">counter</span><span class="p">(</span><span class="n">h3</span><span class="o">-</span><span class="n">cnt</span><span class="p">)</span> <span class="s1">&#39;.&#39;</span> <span class="nb">counter</span><span class="p">(</span><span class="n">h4</span><span class="o">-</span><span class="n">cnt</span><span class="p">)</span> <span class="s1">&#39;.&#39;</span> <span class="nb">counter</span><span class="p">(</span><span class="n">h5</span><span class="o">-</span><span class="n">cnt</span><span class="p">)</span> <span class="s1">&#39;. &#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-content</span> <span class="nt">h6</span><span class="p">::</span><span class="nd">before</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">content</span><span class="p">:</span> <span class="nb">counter</span><span class="p">(</span><span class="n">h2</span><span class="o">-</span><span class="n">cnt</span><span class="p">)</span> <span class="s1">&#39;.&#39;</span> <span class="nb">counter</span><span class="p">(</span><span class="n">h3</span><span class="o">-</span><span class="n">cnt</span><span class="p">)</span> <span class="s1">&#39;.&#39;</span> <span class="nb">counter</span><span class="p">(</span><span class="n">h4</span><span class="o">-</span><span class="n">cnt</span><span class="p">)</span> <span class="s1">&#39;.&#39;</span> <span class="nb">counter</span><span class="p">(</span><span class="n">h5</span><span class="o">-</span><span class="n">cnt</span><span class="p">)</span> <span class="s1">&#39;.&#39;</span> <span class="nb">counter</span><span class="p">(</span><span class="n">h6</span><span class="o">-</span><span class="n">cnt</span><span class="p">)</span> <span class="s1">&#39;. &#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>需要注意的是，这里由于笔者习惯在正文中仅使用&gt;=2 级的标题，因此对 H1 是没有做显示的，如果需要从 H1 开始需要对上述 css 进行简单调整；</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241218190430.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241218190430.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241218190430.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>将该 css 存放在 <code>assets/css/extended</code> 中即可生效。</p>
<h3 id="pagination-update-分页拓展">Pagination Update 分页拓展</h3>
<p>当博客多起来以后，如果在 post 界面不显示页码，以及不能快速的回到首页的话，十分破坏体验，因此简单的添加了回到首页和去到尾页的按钮，方便翻页操作，同时将页码打开，效果如下：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241218190634.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241218190634.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241218190634.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>一、在 <code>hugo.yml</code> 中开启页码</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">params</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">ShowPageNums</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>二、添加跳转至首页和尾页的 button <span class="sidenote-number"><small class="sidenote">参数参考<a href="https://hugo.opendocs.io/templates/pagination/" target="_blank" rel="noopener">分页 | Hugo官方文档</a></small></span></p>
<p>在 <code>layouts/_default/list.html</code> 中的 prev 和 next 处添加 button 如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">footer</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;page-footer&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">nav</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;pagination&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    {{- if $paginator.HasPrev }}
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;last-icon&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;{{ $paginator.First.URL | absURL }}&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="c">&lt;!-- &lt;ion-icon name=&#34;play-back-circle-outline&#34;&gt;&lt;/ion-icon&gt; --&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">span</span><span class="p">&gt;</span><span class="err">&lt;&lt;</span><span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;prev&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;{{ $paginator.Prev.URL | absURL }}&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      «<span class="ni">&amp;nbsp;</span>{{ i18n &#34;prev_page&#34; }}<span class="ni">&amp;nbsp;</span>
</span></span><span class="line"><span class="cl">      {{- if (.Param &#34;ShowPageNums&#34;) }}
</span></span><span class="line"><span class="cl">      {{- sub $paginator.PageNumber 1 }}/{{ $ paginator.TotalPages }}
</span></span><span class="line"><span class="cl">      {{- end }}
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    {{- end }}
</span></span><span class="line"><span class="cl">    {{- if $paginator.HasNext }}
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;next&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;{{ $paginator.Next.URL | absURL }}&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      {{- i18n &#34;next_page&#34; }}<span class="ni">&amp;nbsp;</span>
</span></span><span class="line"><span class="cl">      {{- if (.Param &#34;ShowPageNums&#34;) }}
</span></span><span class="line"><span class="cl">      {{- add 1 $paginator.PageNumber }}/{{ $ paginator.TotalPages }}
</span></span><span class="line"><span class="cl">      {{- end }}<span class="ni">&amp;nbsp;</span>»
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;last-icon&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;{{ $paginator.Last.URL | absURL }}&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="c">&lt;!-- &lt;ion-icon name=&#34;play-forward-circle-outline&#34;&gt;&lt;/ion-icon&gt; --&gt;</span>
</span></span><span class="line"><span class="cl">       <span class="p">&lt;</span><span class="nt">span</span><span class="p">&gt;</span>&gt;&gt;<span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    {{- end }}
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>三、简单设置其样式即可，可以在 <code>assets/css/extended</code> 中随意添加一个 css 文件对默认样式进行覆盖，当然也可以考虑写在主题的 css 中。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">pagination</span> <span class="nt">a</span><span class="p">.</span><span class="nc">last-icon</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">background</span><span class="p">:</span> <span class="kc">unset</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">border</span><span class="p">:</span> <span class="kc">unset</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-size</span><span class="p">:</span> <span class="mf">1.3</span><span class="kt">rem</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="mh">#001e1d</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* padding-top: 2px; */</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-weight</span><span class="p">:</span> <span class="kc">bold</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">pagination</span> <span class="nt">a</span><span class="p">.</span><span class="nc">last-icon</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">primary</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>虽然没有按照该方法实现，但是如果想要更好的分页，可以参考<a href="https://blog.dsrkafuu.net/post/2019/hugo-custom-pagination/" target="_blank" rel="noopener">自定义 Hugo 的分页导航栏 | DSRBLOG</a>
；</p>
<h3 id="pangu-js-引入盘古之白">PanGu JS 引入盘古之白</h3>


<blockquote class="quote-center"><p>為什麼你們就是不能加個空格呢？<span class="sidenote-number"><small class="sidenote"><a href="https://github.com/vinta/pangu.js" target="_blank" rel="noopener">vinta/pangu.js: Paranoid text spacing in JavaScript</a></small></span></p>
<p>如果你跟我一樣，每次看到網頁上的中文字和英文、數字、符號擠在一塊，就會坐立難安，忍不住想在它們之間加個空格。這個外掛（支援 Chrome 和 Firefox）正是你在網路世界走跳所需要的東西，它會自動替你在網頁中所有的中文字和半形的英文、數字、符號之間插入空白。</p>
<p>漢學家稱這個空白字元為「盤古之白 ，因為它劈開了全形字和半形字之間的混沌。另有研究顯示，打字的時候不喜歡在中文和英文之間加空格的人，感情路都走得很辛苦，有七成的比例會在 34 歲的時候跟自己不愛的人結婚，而其餘三成的人最後只能把遺產留給自己的貓。畢竟愛情跟書寫都需要適時地留白。</p>
</blockquote> 

<p>感谢 <code>pangu.js</code> 的作者，以及分享异步加载方案的博主 <span class="sidenote-number"><small class="sidenote"><a href="https://yihui.org/cn/2017/05/pangu/" target="_blank" rel="noopener">盘古之白 - 中英文之间自动加空格 - Yihui Xie | 谢益辉</a></small></span> <span class="sidenote-number"><small class="sidenote"><a href="https://huuuuuuo.github.io/post/hugo%E4%B8%AD%E8%8B%B1%E6%96%87%E4%B9%8B%E9%97%B4%E8%87%AA%E5%8A%A8%E5%8A%A0%E7%A9%BA%E6%A0%BC/" target="_blank" rel="noopener">Hugo：中英文之间自动加空格 | Blog</a></small></span> ， 将该脚本异步引入 hugo 中。</p>
<p>在 <code>layouts\partials\footer.html</code> 中添加即可。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">u</span><span class="p">,</span> <span class="nx">c</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kd">var</span> <span class="nx">d</span> <span class="o">=</span> <span class="nb">document</span><span class="p">,</span> <span class="nx">t</span> <span class="o">=</span> <span class="s1">&#39;script&#39;</span><span class="p">,</span> <span class="nx">o</span> <span class="o">=</span> <span class="nx">d</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="nx">t</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">          <span class="nx">s</span> <span class="o">=</span> <span class="nx">d</span><span class="p">.</span><span class="nx">getElementsByTagName</span><span class="p">(</span><span class="nx">t</span><span class="p">)[</span><span class="mi">0</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">      <span class="nx">o</span><span class="p">.</span><span class="nx">src</span> <span class="o">=</span> <span class="nx">u</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="nx">c</span><span class="p">)</span> <span class="p">{</span> <span class="nx">o</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;load&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span> <span class="nx">c</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span> <span class="p">});</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="nx">s</span><span class="p">.</span><span class="nx">parentNode</span><span class="p">.</span><span class="nx">insertBefore</span><span class="p">(</span><span class="nx">o</span><span class="p">,</span> <span class="nx">s</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">})(</span><span class="s1">&#39;//cdn.bootcss.com/pangu/3.3.0/pangu.min.js&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">pangu</span><span class="p">.</span><span class="nx">spacingPage</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="font-setting-字体修改">Font Setting 字体修改</h3>
<p>本文使用的中文字体为<a href="https://github.com/chawyehsu/lxgw-wenkai-webfont" target="_blank" rel="noopener">霞鹜文楷</a>
 ，感谢开源分享，英文字体可以去 <a href="https://fonts.google.com/specimen/Open&#43;Sans?preview.text=Let%E2%80%99s%20learn%20and%20innovate%20together!" target="_blank" rel="noopener">google font</a>
 中找一个顺眼的，参考上述开源字体的指引，通过 cdn 引入对应的 html 和 css 即可直接在 font-family 中调用。</p>
<ul>
<li>html 插入到：<code>layouts/partials/extend_head.html</code> 中</li>
<li>（如有）css 插入到 <code>assets/css/extended/blank.css</code> 中</li>
</ul>
<p>然后直接在 css 中使用 <code>font-family</code> 调用即可：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">body</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-family</span><span class="p">:</span> <span class="s2">&#34;Open Sans&#34;</span><span class="p">,</span> <span class="s2">&#34;LXGW WenKai&#34;</span><span class="p">,</span> <span class="kc">sans-serif</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="tags-on-post-page-文章-widget-中显示-tag-信息">Tags on Post Page 文章 widget 中显示 tag 信息</h3>
<p>当 post 数量较多时，文章是比较零散的，希望能在 widget 界面展示文章的 Tag 提供更多文章的信息，来建立文章和文章之间的关联。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241219085800.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241219085800.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241219085800.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>找到主题中定义 widget 结构和样式的地方 <code>/layouts/_default/list.html</code> 中的 <code>post-entry</code> 部分 <span class="sidenote-number"><small class="sidenote"><a href="https://github.com/adityatelange/hugo-PaperMod/discussions/606" target="_blank" rel="noopener">How to display tags in the post list? · adityatelange/hugo-PaperMod · Discussion #606</a></small></span> <span class="sidenote-number"><small class="sidenote">主要样式和实现参考：<a href="https://github.com/novikov-ai/novikov-ai.github.io/blob/cc240bfc77819b168f1e70a55d4f7ee44c296ab3/layouts/_default/list.html#L85" target="_blank" rel="noopener">novikov-ai/novikov-ai.github.io</a></small></span> ，使用 go-template 语法遍历&amp;获取具体的 tag <span class="sidenote-number"><small class="sidenote">参考 <a href="https://hugo.opendocs.io/methods/page/params/" target="_blank" rel="noopener">Params | Hugo官方文档</a>
获取 tag</small></span> ，然后将其添加到对应的 meta 模块后面如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">footer</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;entry-footer&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      {{- partial &#34;post_meta.html&#34; . -}}
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    {{- if .Params.tags }}
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;tags&#34;</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;padding: 2px;&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;display: flex; flex-wrap: wrap; justify-content: flex-end; margin-top: 5px;&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        {{ range .Params.tags }}
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/tags/{{ . | urlize }}&#34;</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;margin-right: 5px; 
</span></span></span><span class="line"><span class="cl"><span class="s">                  color: white; 
</span></span></span><span class="line"><span class="cl"><span class="s">                  background-color: rgba(53, 174, 128, 0.7); 
</span></span></span><span class="line"><span class="cl"><span class="s">                  border-radius: 6px; 
</span></span></span><span class="line"><span class="cl"><span class="s">                  padding: 1px 10px;
</span></span></span><span class="line"><span class="cl"><span class="s">                  font-size: 13px;
</span></span></span><span class="line"><span class="cl"><span class="s">                  z-index: 999; &#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          #{{ . }}
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        {{ end }}
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    {{- end }}</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>这里添加 z-index 将 tag 标签移至外层，避免元素置于其余元素下方导致跳转失效。</li>
<li>此外为了使得 tag 和 meta 信息处于同一行而非另起一行，添加如下样式：</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">tags</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* display: inline-block; */</span>
</span></span><span class="line"><span class="cl">  <span class="k">float</span><span class="p">:</span> <span class="kc">right</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="tag-on-meta-info-文章的元信息中显示-tag">Tag on Meta info 文章的元信息中显示 Tag</h3>
<p>在上述的讨论区中 <a href="https://github.com/adityatelange/hugo-PaperMod/discussions/606#discussioncomment-4705301" target="_blank" rel="noopener">mgopsill</a>
 提供了解决方案，感谢其分享，具体操作是通过修改 <code>layouts/partials/post_meta.html</code> 中的 <code>author</code> 部分如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">{{- $author := (partial &#34;author.html&#34; .) }}
</span></span><span class="line"><span class="cl">{{- $tags := (partial &#34;tags.html&#34; .) }}
</span></span><span class="line"><span class="cl">{{- if $tags }}
</span></span><span class="line"><span class="cl">    {{- $scratch.Add &#34;meta&#34; (slice $ author $tags) -}}
</span></span><span class="line"><span class="cl">{{- else}}
</span></span><span class="line"><span class="cl">    {{- $scratch.Add &#34;meta&#34; (slice $ author) -}}
</span></span><span class="line"><span class="cl">{{- end}}</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>并添加对应的 <code>layouts/partials/tags.html</code> 如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">{{- $tags := .Params.tags -}}
</span></span><span class="line"><span class="cl">{{- if $tags -}}
</span></span><span class="line"><span class="cl">  {{- $lastIndex := sub (len $ tags) 1 -}}
</span></span><span class="line"><span class="cl">  {{- range $index, $ tag := $tags -}}
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/tags/{{ $tag | urlize }}&#34;</span><span class="p">&gt;</span> {{ $ tag }}<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    {{- if ne $index $ lastIndex }}<span class="ni">&amp;nbsp;</span>·<span class="ni">&amp;nbsp;</span>{{ end -}}
</span></span><span class="line"><span class="cl">  {{- end -}}
</span></span><span class="line"><span class="cl">{{- end -}}</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="post-widgets-image-to-left-将文章封面图移至侧边">Post Widget&rsquo;s Image to left 将文章封面图移至侧边</h3>
<p>在 post 页面，如果封面图片处于信息块的上方，会导致其对页面空间过度占用，同时不同 size 也会导致呈现效果好坏参差不齐，因此为了使得页面更加美观且高效，参考 <a href="https://cloud.tencent.com/developer/article/1969889" target="_blank" rel="noopener">Hugo博客文章封面图片缩小并移到侧边 | PaperMod主题-素履coder</a>
 的文章，将文章的封面移至侧边；</p>
<p>按照上述博主说的用 <code>div clss=post-info</code> 将整个 post-entry 卡片的内容包括 content、meta、footer 等包裹起来后，将下列两行移至 post-info 的上一行即可，最终结构如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">article</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;{{ $class }}&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  {{- $isHidden := (.Param &#34;cover.hiddenInList&#34;) | default (.Param &#34;cover.hidden&#34;) | default false }}
</span></span><span class="line"><span class="cl">  {{- partial &#34;cover.html&#34; (dict &#34;cxt&#34; . &#34;IsSingle&#34; false &#34;isHidden&#34; $isHidden) }}
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;post-info&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    ...
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>该方法会导致同时影响了文章顶部的图片展示，笔者不同于原文的解决方案，这里通过更具体的 css 选择器做区分即可，还有一些其他的调整如下 <code>assets/css/common/post-entry.css</code>：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="c">/* F2 make the cover in the side on blogs page */</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-entry</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="kc">flex</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">flex-direction</span><span class="p">:</span> <span class="kc">row</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">align-items</span><span class="p">:</span> <span class="kc">center</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-info</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="kc">inline-block</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">overflow</span><span class="p">:</span> <span class="kc">hidden</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">width</span><span class="p">:</span> <span class="mi">90</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">post-entry</span> <span class="p">.</span><span class="nc">entry-cover</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">overflow</span><span class="p">:</span> <span class="kc">hidden</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">padding-right</span><span class="p">:</span> <span class="mi">18</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">height</span><span class="p">:</span> <span class="mi">80</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">width</span><span class="p">:</span> <span class="mi">40</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">margin-bottom</span><span class="p">:</span> <span class="kc">unset</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="something-more-一些别的">Something more 一些别的</h2>
<h3 id="一个多图片居中失败的例子">一个多图片居中失败的例子</h3>
<p>以往使用如下代码使得多张图片同一行居中显示如下图所示，此次在该主题上失效：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241219150455.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241219150455.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20241219150455.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>源码：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">p</span> <span class="na">align</span><span class="o">=</span><span class="s">&#34;center&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34; https://aikenh.cn&#34;</span><span class="p">&gt;&lt;</span><span class="nt">img</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;github&#34;</span> <span class="na">title</span><span class="o">=</span><span class="s">&#34;AikenD&#34;</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34; https://custom-icon-badges.demolab.com/badge/-aiken%20blog-palegreen?style=for-the-badge&amp;logo=package&amp;logoColor=black&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34; https://twitter.com/aiken_h97&#34;</span><span class="p">&gt;&lt;</span><span class="nt">img</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;twitter&#34;</span> <span class="na">title</span><span class="o">=</span><span class="s">&#34;Twitter&#34;</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34; https://custom-icon-badges.demolab.com/badge/-twitter%20aikenh97-plum?style=for-the-badge&amp;logo=package&amp;logoColor=black&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  ...
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以考虑使用 div 或者内联样式去覆盖主题或 hugo 的样式修复该问题如下：</p>
<p>使用 div：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;display: flex; justify-content: center; align-items: center;&#34;</span><span class="p">&gt;</span> 
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://aikenh.cn&#34;</span><span class="p">&gt;&lt;</span><span class="nt">img</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;github&#34;</span> <span class="na">title</span><span class="o">=</span><span class="s">&#34;AikenD&#34;</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://custom-icon-badges.demolab.com/badge/-aiken%20blog-palegreen?style=for-the-badge&amp;logo=package&amp;logoColor=black&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">a</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://twitter.com/aiken_h97&#34;</span><span class="p">&gt;&lt;</span><span class="nt">img</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;twitter&#34;</span> <span class="na">title</span><span class="o">=</span><span class="s">&#34;Twitter&#34;</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://custom-icon-badges.demolab.com/badge/-twitter%20aikenh97-plum?style=for-the-badge&amp;logo=package&amp;logoColor=black&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">a</span><span class="p">&gt;</span> 
</span></span><span class="line"><span class="cl">...
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>使用 inline-style in p:</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">p</span> <span class="na">align</span><span class="o">=</span><span class="s">&#34;center&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://aikenh.cn&#34;</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;display: inline-block; margin: 0 5px;&#34;</span><span class="p">&gt;&lt;</span><span class="nt">img</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;github&#34;</span> <span class="na">title</span><span class="o">=</span><span class="s">&#34;AikenD&#34;</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://custom-icon-badges.demolab.com/badge/-aiken%20blog-palegreen?style=for-the-badge&amp;logo=package&amp;logoColor=black&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://twitter.com/aiken_h97&#34;</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;display: inline-block; margin: 0 5px;&#34;</span><span class="p">&gt;&lt;</span><span class="nt">img</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;twitter&#34;</span> <span class="na">title</span><span class="o">=</span><span class="s">&#34;Twitter&#34;</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://custom-icon-badges.demolab.com/badge/-twitter%20aikenh97-plum?style=for-the-badge&amp;logo=package&amp;logoColor=black&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"> ...
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="一些资源或参考">一些资源或参考</h3>
<ul>
<li>网页图标：<a href="https://favicon.io/" target="_blank" rel="noopener">favicon.io</a>
</li>
<li>一种毛玻璃的实现方式：<a href="https://dev.to/rolandixor/achieving-backdrop-blur-without-backdrop-filter-16ii" target="_blank" rel="noopener">Achieving backdrop blur without &lsquo;backdrop-filter&rsquo; - DEV Community</a>
</li>
<li>给网站添加 loading 页面： <a href="https://dev.to/lensco825/how-to-quickly-add-a-loading-screen-onto-your-website-7ga" target="_blank" rel="noopener">How to Quickly Add a Loading Screen onto your website! - DEV Community</a>
</li>
<li>对 hugo 的理解：<a href="https://kuang.netlify.app/blog/hugo.html" target="_blank" rel="noopener">风月</a>
</li>
</ul>
<h2 id="fi">FI</h2>
<p>文中有任何错误、版权使用不当之处、或者问题欢迎指正和交流，可以留言也可以发邮件，本博客的源码位于：</p>
<p><a href="https://github.com/AikenH/hugoblog" target="_blank" rel="noopener">AikenH/hugoblog: my blog’s hugo variant.</a>
 with submodule <a href="https://github.com/AikenH/papermod-sidebar" target="_blank" rel="noopener">AikenH/papermod-sidebar: my sidebar &amp; transparnet background variant of papermod</a>
</p>
<p>一些处理脚本后续可能会分享到：</p>
<p><a href="https://github.com/AikenH/ManipulateMarkdownNotes" target="_blank" rel="noopener">AikenH/ManipulateMarkdownNotes: manipulate markdown file for publish or some other reason</a>
</p>
<p>目前在 dev 分支完善中。</p>
]]></content:encoded>
    </item>
    <item>
      <title>ShortCode Function Test</title>
      <link>https://aikenh.cn/posts/shotcode_test/</link>
      <pubDate>Sat, 23 Nov 2024 11:30:03 +0000</pubDate>
      <guid>https://aikenh.cn/posts/shotcode_test/</guid>
      <description>test hugo&amp;#39;s shortcode function</description>
      <content:encoded><![CDATA[<p>该文章会测试各种后续修改，包括基础字体，各种后续添加适配的shortcodes： 如 alert、视频、widget ，包括字体渲染，视频渲染，iframe渲染，以及相关的一些其他修改，
同时文章由于引入了大量的js，导致一些功能的渲染速度会下降，这也是我们需要测试的地方，包括找到加载的瓶颈；</p>
<h2 id="extend-shortcodes">Extend ShortCodes</h2>
<h3 id="sidenote">sidenote</h3>
<p>abc</p>
<span class="sidenote-number"><small class="sidenote">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry’s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.</small></span>
<p>def Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry’s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.</p>
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry’s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.</p>
<h3 id="timeline">Timeline</h3>
<p><div class="timeline__row">
    <div class="timeline__time">
        <div class="timeline__time">2023-10-01</div>
        <div class="timeline__split-line"></div>
    </div>
    <div class="timeline__content">
        <div class="timeline__tags">
            <span class="timeline__tag">节日</span>
        </div>
        <a href="">
            <div class="timeline__title">国庆节</div>
        </a>
        
        <div class="timeline__description">
            祖国生日快乐
        </div>
    </div>
</div>


<style>
    .timeline {
        display: flex;
        flex-direction: column;
    }
    
    .timeline__row {
        display: flex;
        padding-left: 4%;
        height: 90px;
    }
    
    .timeline__time {
        flex: 0 0 110px;
        color: var(--content);
        font-size: 17px;
        text-transform: uppercase;
        position: relative;
        display: flex;
        flex-direction: column;
        align-items: center;
        padding: 0.5rem 0;
    }
    
    .timeline__time-text {
        margin: 0;
    }
    
    .timeline__split-line {
        position: absolute;
        top: 0.5rem;
        right: -20px;
        height: 100%;
        width: 2px;
        background-color: #1495d1d6;
        z-index: 0;
    }
    
    .timeline__split-line:before {
        content: "";
        position: absolute;
        top: 24%;
        right: -4px;
        transform: translateY(-50%);
        width: 10px;
        height: 10px;
        background-color: #0479b0;
        box-shadow: 0 0 0 4px var(--theme);
        border-radius: 50%;
        border: 0px solid #84c4e2;
        z-index: -1;
    }
    
    .timeline__content {
        flex: 1;
        margin-left: 4.5rem;
        padding: 0.5rem 0 1.2rem 0;
    }
    
    .timeline__title {
        margin: 0;
        margin-bottom: 2px;
        padding-top: 3px;
        margin-left: 0.5rem;
        color: var(--content);
        font-family: var(--font-family-teshu);
        font-size: 19px;
        font-weight: 600;
        width: fit-content;
        display: inline-block;
        vertical-align: middle;
         
    }
    
    .timeline__tags {
        display: inline-block;
        padding: 0;
        margin-left: 0.3rem;
        align-items: center;
        gap: 0.3rem;
    }
    
    .timeline__tag {
        display: inline-block;
        color: var(--content);
        background-color: #1b577330;
        border: 1.5px solid #84c4e230;
        border-radius: 999px;
        padding: 0rem 0.5rem;
        font-size: 12px;
        white-space: nowrap;
        line-height: 1.4rem;
        opacity: 0.8;
        vertical-align: middle;
         
    }
    
    .timeline__description {
        font-size: 15px;
        line-height: 1.6;
        color: var(--content);
        overflow: hidden;
        text-overflow: ellipsis;
        margin: 0.5rem 0 0.4rem 1.5rem;
         
    }
     
    
    .timeline__tag-style {
        background-color: #c581da;
         
        border-color: #c581da;
         
        color: #FFFFFF;
         
    }
     
    
    .timeline__tag-article {
        background-color: #92d392;
         
        border-color: #92d392;
         
        color: var(--content);
         
    }
     
    
    .timeline__tag-page {
        background-color: #707070;
         
        border-color: #707070;
         
        color: #FFFFFF;
         
    }
    
    @media screen and (max-width: 768px) {
        .timeline__time {
            font-size: 14px;
             
        }
        .timeline__title {
            font-size: 16px;
             
        }
        .timeline__description {
            font-size: 14px;
             
        }
    }
</style>

<div class="timeline__row">
    <div class="timeline__time">
        <div class="timeline__time">2024-01-01</div>
        <div class="timeline__split-line"></div>
    </div>
    <div class="timeline__content">
        <div class="timeline__tags">
            <span class="timeline__tag">节日&amp;计划</span>
        </div>
        <a href="">
            <div class="timeline__title">元旦节</div>
        </a>
        
        <div class="timeline__description">
            上北京er
        </div>
    </div>
</div>


<style>
    .timeline {
        display: flex;
        flex-direction: column;
    }
    
    .timeline__row {
        display: flex;
        padding-left: 4%;
        height: 90px;
    }
    
    .timeline__time {
        flex: 0 0 110px;
        color: var(--content);
        font-size: 17px;
        text-transform: uppercase;
        position: relative;
        display: flex;
        flex-direction: column;
        align-items: center;
        padding: 0.5rem 0;
    }
    
    .timeline__time-text {
        margin: 0;
    }
    
    .timeline__split-line {
        position: absolute;
        top: 0.5rem;
        right: -20px;
        height: 100%;
        width: 2px;
        background-color: #1495d1d6;
        z-index: 0;
    }
    
    .timeline__split-line:before {
        content: "";
        position: absolute;
        top: 24%;
        right: -4px;
        transform: translateY(-50%);
        width: 10px;
        height: 10px;
        background-color: #0479b0;
        box-shadow: 0 0 0 4px var(--theme);
        border-radius: 50%;
        border: 0px solid #84c4e2;
        z-index: -1;
    }
    
    .timeline__content {
        flex: 1;
        margin-left: 4.5rem;
        padding: 0.5rem 0 1.2rem 0;
    }
    
    .timeline__title {
        margin: 0;
        margin-bottom: 2px;
        padding-top: 3px;
        margin-left: 0.5rem;
        color: var(--content);
        font-family: var(--font-family-teshu);
        font-size: 19px;
        font-weight: 600;
        width: fit-content;
        display: inline-block;
        vertical-align: middle;
         
    }
    
    .timeline__tags {
        display: inline-block;
        padding: 0;
        margin-left: 0.3rem;
        align-items: center;
        gap: 0.3rem;
    }
    
    .timeline__tag {
        display: inline-block;
        color: var(--content);
        background-color: #1b577330;
        border: 1.5px solid #84c4e230;
        border-radius: 999px;
        padding: 0rem 0.5rem;
        font-size: 12px;
        white-space: nowrap;
        line-height: 1.4rem;
        opacity: 0.8;
        vertical-align: middle;
         
    }
    
    .timeline__description {
        font-size: 15px;
        line-height: 1.6;
        color: var(--content);
        overflow: hidden;
        text-overflow: ellipsis;
        margin: 0.5rem 0 0.4rem 1.5rem;
         
    }
     
    
    .timeline__tag-style {
        background-color: #c581da;
         
        border-color: #c581da;
         
        color: #FFFFFF;
         
    }
     
    
    .timeline__tag-article {
        background-color: #92d392;
         
        border-color: #92d392;
         
        color: var(--content);
         
    }
     
    
    .timeline__tag-page {
        background-color: #707070;
         
        border-color: #707070;
         
        color: #FFFFFF;
         
    }
    
    @media screen and (max-width: 768px) {
        .timeline__time {
            font-size: 14px;
             
        }
        .timeline__title {
            font-size: 16px;
             
        }
        .timeline__description {
            font-size: 14px;
             
        }
    }
</style>
</p>
<h3 id="chat">Chat</h3>

<div class="chat --other">
    <div class="chat__inner">
        <div class="chat__meta">metisy&nbsp;&nbsp;&nbsp;2024-11-25 19:31</div>
        <div class="chat__text">
            
这是左边的消息内容。

        </div>
    </div>
</div>


<style>
    .chat {
        margin: 10px;
        padding: 10px;
        position: relative;
         
        transition: transform 0.2s;
         
        max-width: 80%;
        min-width: 15%;
    }
    
    .chat:hover {
        transform: scale(1.05);
    }
    
    .chat.--self {
        text-align: left;
        background-color: #ecf5ff;
        color: #000000;
        border-radius: 15px;
        width: fit-content;
        margin-left: auto;
    }
     
    
    .chat.--self::before {
        content: "";
        position: absolute;
        right: -18px;
         
        bottom: 5px;
        transform: translateY(-50%);
        border-width: 15px 0 0 20px;
        border-style: solid;
        border-color: transparent transparent transparent #ecf5ff;
         
    }
     
    
    .chat.--other {
        text-align: left;
        background-color: #ffecec;
        color: #333;
        border-radius: 15px;
        position: relative;
        width: fit-content;
    }
     
    
    .chat.--other::before {
        content: "";
        position: absolute;
        left: -18px;
        bottom: 5px;
        transform: translateY(-50%);
        border-width: 15px 20px 0 0;
        border-style: solid;
        border-color: transparent #ffecec transparent transparent;
    }
     
    
    .chat__meta {
        font-weight: bold;
        font-size: 0.67em;
        color: #707070;
        margin-bottom: 5px;
    }
     
    
    .chat__text {
        font-size: 0.9em;
        margin-left: 10px;
        word-break: break-all;
    }
    
    [data-scheme="dark"] {
        .chat.--self {
            color: #fefefe;
            background-color: #253958;
        }
        .chat.--self::before {
            border-color: transparent transparent transparent #253958;
        }
        .chat.--other {
            color: #fefefe;
            background-color: #1a1a1a;
        }
        .chat.--other::before {
            border-color: transparent #1a1a1a transparent transparent;
        }
        .chat__meta {
            color: #b1b1b1;
        }
    }
</style>


<div class="chat --self">
    <div class="chat__inner">
        <div class="chat__meta" style="text-align: right;">2024-11-25 19:32&nbsp;&nbsp;&nbsp;aikenh</div>
        <div class="chat__text">
             
这是右边的消息内容，测试长长长长长长长长长长长长长长长长长长长长长长长长度。

        </div>
    </div>
</div>


<style>
    .chat {
        margin: 10px;
        padding: 10px;
        position: relative;
         
        transition: transform 0.2s;
         
        max-width: 80%;
        min-width: 15%;
    }
    
    .chat:hover {
        transform: scale(1.05);
    }
    
    .chat.--self {
        text-align: left;
        background-color: #ecf5ff;
        color: #000000;
        border-radius: 15px;
        width: fit-content;
        margin-left: auto;
    }
     
    
    .chat.--self::before {
        content: "";
        position: absolute;
        right: -18px;
         
        bottom: 5px;
        transform: translateY(-50%);
        border-width: 15px 0 0 20px;
        border-style: solid;
        border-color: transparent transparent transparent #ecf5ff;
         
    }
     
    
    .chat.--other {
        text-align: left;
        background-color: #ffecec;
        color: #333;
        border-radius: 15px;
        position: relative;
        width: fit-content;
    }
     
    
    .chat.--other::before {
        content: "";
        position: absolute;
        left: -18px;
        bottom: 5px;
        transform: translateY(-50%);
        border-width: 15px 20px 0 0;
        border-style: solid;
        border-color: transparent #ffecec transparent transparent;
    }
     
    
    .chat__meta {
        font-weight: bold;
        font-size: 0.67em;
        color: #707070;
        margin-bottom: 5px;
    }
     
    
    .chat__text {
        font-size: 0.9em;
        margin-left: 10px;
        word-break: break-all;
    }
    
    [data-scheme="dark"] {
        .chat.--self {
            color: #fefefe;
            background-color: #253958;
        }
        .chat.--self::before {
            border-color: transparent transparent transparent #253958;
        }
        .chat.--other {
            color: #fefefe;
            background-color: #1a1a1a;
        }
        .chat.--other::before {
            border-color: transparent #1a1a1a transparent transparent;
        }
        .chat__meta {
            color: #b1b1b1;
        }
    }
</style>

<h3 id="quota-center">quota-center</h3>


<blockquote class="quote-center">
        <p>十里青山远，潮平路带沙<br>数声啼鸟怨年华<br>又是凄凉时候，在天涯<br>白露收残月，清风散晓霞<br>绿杨堤畔问荷花<br>记得年时沽酒，那人家</p></blockquote> 

<h3 id="quota">quota</h3>


<blockquote class="quote">
        <p>十里青山远，潮平路带沙。数声啼鸟怨年华。又是凄凉时候，在天涯。白露收残月，清风散晓霞。绿杨堤畔问荷花。记得年时沽酒，那人家。</p></blockquote> 

<h3 id="simple-notice">simple-notice</h3>



<div class="simple-notice simple-notice-warning" >
    <div class="simple-notice-title"><svg xmlns="http://www.w3.org/2000/svg" class="icon simple-notice-icon" viewBox="0 0 512 512"><path d="M114.57 76.07a45.71 45.71 0 00-67.51-6.41c-17.58 16.18-19 43.52-4.75 62.77l91.78 123-92.33 124.15c-14.23 19.25-13.11 46.59 4.74 62.77a45.71 45.71 0 0067.5-6.41L242.89 262.7a12.14 12.14 0 000-14.23zm355.67 303.51l-92.33-124.13 91.78-123c14.22-19.25 12.83-46.59-4.75-62.77a45.71 45.71 0 00-67.51 6.41l-128 172.12a12.14 12.14 0 000 14.23L398 435.94a45.71 45.71 0 0067.51 6.41c17.84-16.18 18.96-43.52 4.73-62.77z"/></svg></div><p>十里青山远，潮平路带沙。数声啼鸟怨年华。又是凄凉时候，在天涯。白露收残月，清风散晓霞。绿杨堤畔问荷花。记得年时沽酒，那人家。</p></div>




<div class="simple-notice simple-notice-info" >
    <div class="simple-notice-title"><svg xmlns="http://www.w3.org/2000/svg" class="icon simple-notice-icon" viewBox="0 0 192 512"><path d="M20 424.23h20V279.77H20a20 20 0 01-20-20V212a20 20 0 0120-20h112a20 20 0 0120 20v212.23h20a20 20 0 0120 20V492a20 20 0 01-20 20H20a20 20 0 01-20-20v-47.77a20 20 0 0120-20zM96 0a72 72 0 100 144A72 72 0 0096 0z"/></svg></div><p>十里青山远，潮平路带沙。数声啼鸟怨年华。又是凄凉时候，在天涯。白露收残月，清风散晓霞。绿杨堤畔问荷花。记得年时沽酒，那人家。</p></div>




<div class="simple-notice simple-notice-tip" >
    <div class="simple-notice-title"><svg xmlns="http://www.w3.org/2000/svg" class="icon simple-notice-icon" viewBox="0 0 512 512"><path d="M173.9 439.4L7.5 273c-10-10-10-26.2 0-36.2l36.2-36.2c10-10 26.2-10 36.2 0L192 312.69l240.1-240.1c10-10 26.2-10 36.2 0l36.2 36.21c10 10 10 26.2 0 36.2L210.1 439.4c-10 10-26.2 10-36.2 0z"/></svg></div><p>十里青山远，潮平路带沙。数声啼鸟怨年华。又是凄凉时候，在天涯。白露收残月，清风散晓霞。绿杨堤畔问荷花。记得年时沽酒，那人家。</p></div>

<h3 id="notice">notice</h3>



<div class="notice notice-warning" >
    <div class="notice-title"><svg xmlns="http://www.w3.org/2000/svg" class="icon notice-icon" viewBox="0 0 576 512"><path d="M570 440c18 32-5 72-42 72H48c-37 0-60-40-42-72L246 24c19-32 65-32 84 0l240 416zm-282-86a46 46 0 100 92 46 46 0 000-92zm-44-165l8 136c0 6 5 11 12 11h48c7 0 12-5 12-11l8-136c0-7-5-13-12-13h-64c-7 0-12 6-12 13z"/></svg></div><p>十里青山远，潮平路带沙。数声啼鸟怨年华。又是凄凉时候，在天涯。白露收残月，清风散晓霞。绿杨堤畔问荷花。记得年时沽酒，那人家。</p></div>

<h3 id="github-widget">github widget</h3>


<div class="github">
    <div class="logo">
        <svg xmlns="http://www.w3.org/2000/svg" class="icon github-icon" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M2 2.5C2 1.83696 2.26339 1.20107 2.73223 0.732233C3.20108 0.263392 3.83696 0 4.5 0L13.25 0C13.4489 0 13.6397 0.0790176 13.7803 0.21967C13.921 0.360322 14 0.551088 14 0.75V13.25C14 13.4489 13.921 13.6397 13.7803 13.7803C13.6397 13.921 13.4489 14 13.25 14H10.75C10.5511 14 10.3603 13.921 10.2197 13.7803C10.079 13.6397 10 13.4489 10 13.25C10 13.0511 10.079 12.8603 10.2197 12.7197C10.3603 12.579 10.5511 12.5 10.75 12.5H12.5V10.5H4.5C4.30308 10.5 4.11056 10.5582 3.94657 10.6672C3.78257 10.7762 3.65442 10.9312 3.57816 11.1128C3.50191 11.2943 3.48096 11.4943 3.51793 11.6878C3.5549 11.8812 3.64816 12.0594 3.786 12.2C3.92524 12.3422 4.0023 12.5338 4.00024 12.7328C3.99818 12.9318 3.91716 13.1218 3.775 13.261C3.63285 13.4002 3.4412 13.4773 3.24222 13.4752C3.04325 13.4732 2.85324 13.3922 2.714 13.25C2.25571 12.7829 1.99929 12.1544 2 11.5V2.5ZM12.5 1.5V9H4.5C4.144 9 3.806 9.074 3.5 9.208V2.5C3.5 2.23478 3.60536 1.98043 3.79289 1.79289C3.98043 1.60536 4.23478 1.5 4.5 1.5H12.5ZM5 12.25V15.5C5 15.5464 5.01293 15.5919 5.03734 15.6314C5.06175 15.6709 5.09667 15.7028 5.1382 15.7236C5.17972 15.7444 5.22621 15.7532 5.27245 15.749C5.31869 15.7448 5.36286 15.7279 5.4 15.7L6.85 14.613C6.89328 14.5805 6.94591 14.563 7 14.563C7.05409 14.563 7.10673 14.5805 7.15 14.613L8.6 15.7C8.63714 15.7279 8.68131 15.7448 8.72755 15.749C8.77379 15.7532 8.82028 15.7444 8.8618 15.7236C8.90333 15.7028 8.93826 15.6709 8.96266 15.6314C8.98707 15.5919 9 15.5464 9 15.5V12.25C9 12.1837 8.97366 12.1201 8.92678 12.0732C8.87989 12.0263 8.81631 12 8.75 12H5.25C5.1837 12 5.12011 12.0263 5.07322 12.0732C5.02634 12.1201 5 12.1837 5 12.25Z"/></svg>
        <a class="name" href=https://github.com/guanqr/Organic-Carbon-Estimating target="_blank">Organic-Carbon-Estimating</a>
    </div>
    <div class="description">A program used in estimating organic carbon stocks in oceans. 计算指定海域的有机碳存量，包括颗粒有机碳与溶解有机碳，数据依赖于 NASA 中分辨率成像光谱仪 MODIS 遥感产品。</div> 
    <div class="language">
        <span class="language-color" style="background-color: #e16737"></span>
        <span class="language-name">MATLAB</span>
    </div>
</div>

<h3 id="align">align</h3>
<p style="text-align:left">文字居左</p>

<p style="text-align:center">文字居中</p>

<p style="text-align:right">文字居右</p>

<h3 id="video-function">Video Function</h3>
<h4 id="bilibili">bilibili</h4>













    




<div style="margin: 10px 0 20px 0;">
  
  <div style="margin: 5px 0;">
    <a href="https://www.bilibili.com/video/BV12NpBeYErP/">BV12NpBeYErP</a>
  </div>

  <div style="position:relative; padding-bottom:75%; width:100%; height:0">
    <iframe src="//player.bilibili.com/player.html?bvid=BV12NpBeYErP&page=1&autoplay=0"       
        scrolling="no" border="0"
        frameborder="no" 
        framespacing="0" 
        allowfullscreen="true" 
        style="position:absolute; height: 100%; width: 100%;">
    </iframe>
  </div>
</div>
<h2 id="markdown-function-expand-support">Markdown Function Expand Support</h2>
<h3 id="pangujs">pangujs</h3>
<p>这是一段测试pangu之白的article，看看渲染出来的效果如何</p>
<h3 id="alert-block">Alert Block</h3>
<p>接下来测试各个关键词的渲染效果并进行调整， 首先就是 Note</p>



  
  

<blockquote class="alert-blockquote alert-note">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Note</span>
  </p>
  <p>test note block&rsquo;s style.</p>

</blockquote>
<p>其次是：important</p>



  
  

<blockquote class="alert-blockquote alert-important">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0 1 14.25 13H8.06l-2.573 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25Zm7 2.25v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 9a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path>
    </svg>
    <span>Important</span>
  </p>
  <p>重要内容</p>

</blockquote>
<p>接着是：tip</p>



  
  

<blockquote class="alert-blockquote alert-tip">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z"></path>
    </svg>
    <span>Tip</span>
  </p>
  <p>这是一些提示内容</p>

</blockquote>
<p>再次是 warning</p>



  
  

<blockquote class="alert-blockquote alert-warning">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path>
    </svg>
    <span>Warning</span>
  </p>
  <p>这是一些告警内容</p>

</blockquote>
<p>最后是caution</p>



  
  

<blockquote class="alert-blockquote alert-caution">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Caution</span>
  </p>
  <p>重要内容</p>

</blockquote>
<p>然后测试一个自己添加的</p>



  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>总结</p>

</blockquote>
<h3 id="mermaid">mermaid</h3>
<p>mermaid 的跟随主题切换更改渲染的方式一直不work，暂时使用black theme加渲染的方式做处理。</p>
<pre class="mermaid">flowchart LR

G[工作强度]
G --&gt; A
G --&gt; C
G --&gt; E
A[&#34;主动&#34;策略] --&gt; B[卷，按照表现辞退， 工作时间长，薪资构成=基本工资+基金表现*贡献Rate]
C[&#34;被动&#34;跟踪] --&gt; D[WLB, 固定工资，晋升-&gt;管理]
E[&#34;混合&#34;] --&gt; F[介于两者之间，薪资与公司表现挂钩]
  </pre>
  <p>下面给出一个官方的不同实例来看不同的模式下的不同渲染情况</p>
<pre class="mermaid">sequenceDiagram
    participant Alice
    participant Bob
    Alice-&gt;&gt;John: Hello John, how are you?
    loop Healthcheck
        John-&gt;&gt;John: Fight against hypochondria
    end
    Note right of John: Rational thoughts &lt;br/&gt;prevail!
    John--&gt;&gt;Alice: Great!
    John-&gt;&gt;Bob: How about you?
    Bob--&gt;&gt;John: Jolly good!
  </pre>
  <p>最后再来一个常规的流程图，或者说是概率图</p>
<pre class="mermaid">---
title: Action Distrubution based on Feature
---
flowchart LR

A[DragonBeenAtkBySomeone] --&gt; B1[Value 1] 
B1 -- 60% --&gt; C[Atk Target is Dragon]
B1 -- 40% --&gt; D[Other Action]

A --&gt; B2[Value 0] --&gt; E[All Action Possible]
  </pre>
  <h2 id="default-shortcodes">Default ShortCodes</h2>
<h3 id="gist">gist</h3>
<p><a href="https://www.andbible.com/post/hugo-content-management-shortcodes/" target="_blank" rel="noopener">https://www.andbible.com/post/hugo-content-management-shortcodes/</a>
</p>
<script src="https://gist.github.com/spf13/7896402.js?file=img.html"></script>

<h3 id="youtube">youtube</h3>


    
    <div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/w7Ft2ymGmfc?autoplay=0&controls=1&end=0&loop=0&mute=0&start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"
      ></iframe>
    </div>

<h3 id="twitter">twitter</h3>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Owl bet you&#39;ll lose this staring contest 🦉 <a href="https://t.co/eJh4f2zncC">pic.twitter.com/eJh4f2zncC</a></p>&mdash; San Diego Zoo Wildlife Alliance (@sandiegozoo) <a href="https://twitter.com/sandiegozoo/status/1453110110599868418?ref_src=twsrc%5Etfw">October 26, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


<h3 id="ins">ins</h3>
<blockquote
    class="instagram-media"
    data-instgrm-captioned
    data-instgrm-permalink="https://www.instagram.com/p/CxOWiQNP2MO"
    data-instgrm-version="14"
    style="
      background: #fff;
      border: 0;
      border-radius: 3px;
      box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.5), 0 1px 10px 0 rgba(0, 0, 0, 0.15);
      margin: 1px;
      max-width: 540px;
      min-width: 326px;
      padding: 0;
      width: 99.375%;
      width: -webkit-calc(100% - 2px);
      width: calc(100% - 2px);
    "
  >
    <div style="padding: 16px">
      <a
        href="https://www.instagram.com/p/CxOWiQNP2MO"
        style="
          background: #ffffff;
          line-height: 0;
          padding: 0 0;
          text-align: center;
          text-decoration: none;
          width: 100%;
        "
        target="_blank"
      >
        <div style="display: flex; flex-direction: row; align-items: center">
          <div
            style="
              background-color: #f4f4f4;
              border-radius: 50%;
              flex-grow: 0;
              height: 40px;
              margin-right: 14px;
              width: 40px;
            "
          ></div>
          <div
            style="
              display: flex;
              flex-direction: column;
              flex-grow: 1;
              justify-content: center;
            "
          >
            <div
              style="
                background-color: #f4f4f4;
                border-radius: 4px;
                flex-grow: 0;
                height: 14px;
                margin-bottom: 6px;
                width: 100px;
              "
            ></div>
            <div
              style="
                background-color: #f4f4f4;
                border-radius: 4px;
                flex-grow: 0;
                height: 14px;
                width: 60px;
              "
            ></div>
          </div>
        </div>
        <div style="padding: 19% 0"></div>
        <div
          style="display: block; height: 50px; margin: 0 auto 12px; width: 50px"
        >
          <svg
            width="50px"
            height="50px"
            viewBox="0 0 60 60"
            version="1.1"
            xmlns="https://www.w3.org/2000/svg"
            xmlns:xlink="https://www.w3.org/1999/xlink"
          >
            <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
              <g transform="translate(-511.000000, -20.000000)" fill="#000000">
                <g>
                  <path
                    d="M556.869,30.41 C554.814,30.41 553.148,32.076 553.148,34.131 C553.148,36.186 554.814,37.852 556.869,37.852 C558.924,37.852 560.59,36.186 560.59,34.131 C560.59,32.076 558.924,30.41 556.869,30.41 M541,60.657 C535.114,60.657 530.342,55.887 530.342,50 C530.342,44.114 535.114,39.342 541,39.342 C546.887,39.342 551.658,44.114 551.658,50 C551.658,55.887 546.887,60.657 541,60.657 M541,33.886 C532.1,33.886 524.886,41.1 524.886,50 C524.886,58.899 532.1,66.113 541,66.113 C549.9,66.113 557.115,58.899 557.115,50 C557.115,41.1 549.9,33.886 541,33.886 M565.378,62.101 C565.244,65.022 564.756,66.606 564.346,67.663 C563.803,69.06 563.154,70.057 562.106,71.106 C561.058,72.155 560.06,72.803 558.662,73.347 C557.607,73.757 556.021,74.244 553.102,74.378 C549.944,74.521 548.997,74.552 541,74.552 C533.003,74.552 532.056,74.521 528.898,74.378 C525.979,74.244 524.393,73.757 523.338,73.347 C521.94,72.803 520.942,72.155 519.894,71.106 C518.846,70.057 518.197,69.06 517.654,67.663 C517.244,66.606 516.755,65.022 516.623,62.101 C516.479,58.943 516.448,57.996 516.448,50 C516.448,42.003 516.479,41.056 516.623,37.899 C516.755,34.978 517.244,33.391 517.654,32.338 C518.197,30.938 518.846,29.942 519.894,28.894 C520.942,27.846 521.94,27.196 523.338,26.654 C524.393,26.244 525.979,25.756 528.898,25.623 C532.057,25.479 533.004,25.448 541,25.448 C548.997,25.448 549.943,25.479 553.102,25.623 C556.021,25.756 557.607,26.244 558.662,26.654 C560.06,27.196 561.058,27.846 562.106,28.894 C563.154,29.942 563.803,30.938 564.346,32.338 C564.756,33.391 565.244,34.978 565.378,37.899 C565.522,41.056 565.552,42.003 565.552,50 C565.552,57.996 565.522,58.943 565.378,62.101 M570.82,37.631 C570.674,34.438 570.167,32.258 569.425,30.349 C568.659,28.377 567.633,26.702 565.965,25.035 C564.297,23.368 562.623,22.342 560.652,21.575 C558.743,20.834 556.562,20.326 553.369,20.18 C550.169,20.033 549.148,20 541,20 C532.853,20 531.831,20.033 528.631,20.18 C525.438,20.326 523.257,20.834 521.349,21.575 C519.376,22.342 517.703,23.368 516.035,25.035 C514.368,26.702 513.342,28.377 512.574,30.349 C511.834,32.258 511.326,34.438 511.181,37.631 C511.035,40.831 511,41.851 511,50 C511,58.147 511.035,59.17 511.181,62.369 C511.326,65.562 511.834,67.743 512.574,69.651 C513.342,71.625 514.368,73.296 516.035,74.965 C517.703,76.634 519.376,77.658 521.349,78.425 C523.257,79.167 525.438,79.673 528.631,79.82 C531.831,79.965 532.853,80.001 541,80.001 C549.148,80.001 550.169,79.965 553.369,79.82 C556.562,79.673 558.743,79.167 560.652,78.425 C562.623,77.658 564.297,76.634 565.965,74.965 C567.633,73.296 568.659,71.625 569.425,69.651 C570.167,67.743 570.674,65.562 570.82,62.369 C570.966,59.17 571,58.147 571,50 C571,41.851 570.966,40.831 570.82,37.631"
                  ></path>
                </g>
              </g>
            </g>
          </svg>
        </div>
        <div style="padding-top: 8px">
          <div
            style="
              color: #3897f0;
              font-family: Arial, sans-serif;
              font-size: 14px;
              font-style: normal;
              font-weight: 550;
              line-height: 18px;
            "
          >
            View this post on Instagram
          </div>
        </div>
        <div style="padding: 12.5% 0"></div>
        <div
          style="
            display: flex;
            flex-direction: row;
            margin-bottom: 14px;
            align-items: center;
          "
        >
          <div>
            <div
              style="
                background-color: #f4f4f4;
                border-radius: 50%;
                height: 12.5px;
                width: 12.5px;
                transform: translateX(0px) translateY(7px);
              "
            ></div>
            <div
              style="
                background-color: #f4f4f4;
                height: 12.5px;
                transform: rotate(-45deg) translateX(3px) translateY(1px);
                width: 12.5px;
                flex-grow: 0;
                margin-right: 14px;
                margin-left: 2px;
              "
            ></div>
            <div
              style="
                background-color: #f4f4f4;
                border-radius: 50%;
                height: 12.5px;
                width: 12.5px;
                transform: translateX(9px) translateY(-18px);
              "
            ></div>
          </div>
          <div style="margin-left: 8px">
            <div
              style="
                background-color: #f4f4f4;
                border-radius: 50%;
                flex-grow: 0;
                height: 20px;
                width: 20px;
              "
            ></div>
            <div
              style="
                width: 0;
                height: 0;
                border-top: 2px solid transparent;
                border-left: 6px solid #f4f4f4;
                border-bottom: 2px solid transparent;
                transform: translateX(16px) translateY(-4px) rotate(30deg);
              "
            ></div>
          </div>
          <div style="margin-left: auto">
            <div
              style="
                width: 0px;
                border-top: 8px solid #f4f4f4;
                border-right: 8px solid transparent;
                transform: translateY(16px);
              "
            ></div>
            <div
              style="
                background-color: #f4f4f4;
                flex-grow: 0;
                height: 12px;
                width: 16px;
                transform: translateY(-4px);
              "
            ></div>
            <div
              style="
                width: 0;
                height: 0;
                border-top: 8px solid #f4f4f4;
                border-left: 8px solid transparent;
                transform: translateY(-4px) translateX(8px);
              "
            ></div>
          </div>
        </div>
        <div
          style="
            display: flex;
            flex-direction: column;
            flex-grow: 1;
            justify-content: center;
            margin-bottom: 24px;
          "
        >
          <div
            style="
              background-color: #f4f4f4;
              border-radius: 4px;
              flex-grow: 0;
              height: 14px;
              margin-bottom: 6px;
              width: 224px;
            "
          ></div>
          <div
            style="
              background-color: #f4f4f4;
              border-radius: 4px;
              flex-grow: 0;
              height: 14px;
              width: 144px;
            "
          ></div></div
      ></a>
    </div>
  </blockquote><script async src="//www.instagram.com/embed.js"></script>
<h2 id="fi">FI</h2>
]]></content:encoded>
    </item>
    <item>
      <title>头文件互相包含</title>
      <link>https://aikenh.cn/posts/ts1_%E5%A4%B4%E6%96%87%E4%BB%B6%E4%BA%92%E7%9B%B8%E5%8C%85%E5%90%AB/</link>
      <pubDate>Tue, 22 Oct 2024 17:05:32 +0000</pubDate>
      <guid>https://aikenh.cn/posts/ts1_%E5%A4%B4%E6%96%87%E4%BB%B6%E4%BA%92%E7%9B%B8%E5%8C%85%E5%90%AB/</guid>
      <description>使用类前置声明来解决CPP头文件相互包含带来的编译问题</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-error">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Error</span>
  </p>
  <p>编写 C++ 代码时偶尔会遇到两个类需要相互引用的情况，如果在 h 文件中相互包含会导致 &ldquo;has not been declared&rdquo; 等声明问题，此时需要使用前置声明的方式来解决该问题</p>

</blockquote>
<h3 id="code-example">Code Example</h3>
<p>以一个实际场景为例：假设有工具类 Search Helper 提供一系列搜索功能，还有另一个 ObjectAttr 定义一系列操作对象的属性，在 ObjectAttr 中需要引用 SearchHelper 提供的某个基础函数，而 SearchHelper 中部分针对 ObjectAttr 设计的某些功能则需要将 ObjectAttr 中的类作为入参，此时我们可能会在 h 文件中相互引用；</p>
<p>在 obj_definition.h 中有 <code>GetSelfNearObj</code> 函数，其过程中需要调用 search_helper 中的 <code>GetDistObj</code> 函数进行辅助运算</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&#34;util/search_helper.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="k">namespace</span> <span class="n">object_info</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">class</span> <span class="nc">ObjectAttr</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">		<span class="n">LocationType</span> <span class="n">location</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="kt">int</span> <span class="n">ObjId</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="kt">int</span> <span class="n">NearObjId</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">private</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">		<span class="kt">void</span> <span class="n">GetSelfNearObj</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">	<span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在 search_helper.h 中有以下函数定义</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&#34;base/obj_definition.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="k">namespace</span> <span class="n">search_helper</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">class</span> <span class="nc">SearchHelper</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">		<span class="kt">int</span> <span class="n">GetDistObj</span><span class="p">(</span><span class="k">const</span> <span class="n">object_info</span><span class="o">::</span><span class="n">ObjectAttr</span> <span class="o">&amp;</span> <span class="n">obj1</span><span class="p">,</span> <span class="k">const</span> <span class="n">object_info</span><span class="o">::</span><span class="n">ObjectAttr</span> <span class="o">&amp;</span> <span class="n">obj2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这种情况下编译会出现未定义，未声明，not a type 之类<strong>缺少类型说明符</strong>的错误。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span></span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code>error: ... has not been declared</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="fix--analysis">Fix &amp; Analysis</h3>
<p>上述错误是由于两个文件构成了循环依赖，类 <code>SearchHelper</code> 依赖于 <code>ObjectAttr</code>，<code>ObjectAttr</code> 又依赖于 <code>SearchHelper</code>；因此编译器会报错导致无法通过编译；</p>
<p>在这种情况下，可以通过前向声明的方式来解决这种问题，即不去进行循环引用，在search_helper 中不 <code>#include obj_definition.h</code>，但是对需要的 <code>ObjectAttr</code> 进行一个空声明，然后在 .cpp 中 <code>#include obj_definition.h</code>  具体如下，将 H 文件修改为；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">namespace</span> <span class="n">objct_info</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">class</span> <span class="nc">ObjectAttr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="n">search_helper</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">class</span> <span class="nc">SearchHelper</span><span class="p">{</span>
</span></span><span class="line"><span class="cl"> 	<span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl"> 		<span class="kt">int</span> <span class="n">GetDistObj</span><span class="p">(</span><span class="k">const</span> <span class="n">object_info</span><span class="o">::</span><span class="n">ObjectAttr</span> <span class="o">&amp;</span> <span class="n">obj1</span><span class="p">,</span> <span class="k">const</span> <span class="n">object_info</span><span class="o">::</span><span class="n">ObjectAttr</span> <span class="o">&amp;</span> <span class="n">obj2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在对应的 <code>.cpp</code> 文件中添加对 <code>obj_definition</code> 的包含，这样在编译过程中，<code>ObjectAttr</code> 会被自动链接到正确的定义；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&#34;base/obj_definition.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// origin cpp file below...
</span></span></span><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>上述例子展示了不同命名空间下的情况，这里秉持的原则就是不同文件中对类的前置声明要保持一致，无论是命名空间、参数、类型等，在同一个命名空间中的情况要更简单，可以以此类推，这里不再赘述；</p>
<h3 id="reference">Reference</h3>
<ol>
<li><a href="https://blog.csdn.net/hfutljx/article/details/81508740" target="_blank" rel="noopener">c++ 头文件互相包含问题</a>
</li>
<li><a href="https://www.cnblogs.com/staring-hxs/p/3244251.html" target="_blank" rel="noopener">c++ 类声明 类前置声明范例</a>
</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>Docker Troubleshoot</title>
      <link>https://aikenh.cn/posts/docker_troubleshoot/</link>
      <pubDate>Tue, 09 Jul 2024 15:52:46 +0000</pubDate>
      <guid>https://aikenh.cn/posts/docker_troubleshoot/</guid>
      <description>&lt;h2 id=&#34;troubleshooting-故障排查&#34;&gt;TroubleShooting 故障排查&lt;/h2&gt;
&lt;h3 id=&#34;credential-related&#34;&gt;Credential Related&lt;/h3&gt;



  
  

&lt;blockquote class=&#34;alert-blockquote alert-error&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Error&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;error getting credentials - err: exec: &amp;ldquo;docker-credential-desktop.exe&amp;rdquo;: executable file not found in $PATH, out: ``&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h2 id="troubleshooting-故障排查">TroubleShooting 故障排查</h2>
<h3 id="credential-related">Credential Related</h3>



  
  

<blockquote class="alert-blockquote alert-error">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Error</span>
  </p>
  <p>error getting credentials - err: exec: &ldquo;docker-credential-desktop.exe&rdquo;: executable file not found in $PATH, out: ``</p>

</blockquote>
<p>解决方法根据情况可能是以下的两种：<a href="https://forums.docker.com/t/docker-credential-desktop-exe-executable-file-not-found-in-path-using-wsl2/100225/3" target="_blank" rel="noopener">参考资料1</a>
 | <a href="https://peterbillzhang.medium.com/fix-wsl2-docker-error-f4e6502c38a4" target="_blank" rel="noopener">参考资料2 WSL2</a>
 | <a href="https://stackoverflow.com/questions/65896681/exec-docker-credential-desktop-exe-executable-file-not-found-in-path" target="_blank" rel="noopener">参考资料3</a>
</p>
<p>WSL2 相关的情况下可能需要执行以下的挂载：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 执行挂载</span>
</span></span><span class="line"><span class="cl">sudo ln -s /mnt/c/Program<span class="se">\ </span>Files/Docker/Docker/resources/bin/docker-credential-desktop.exe /usr/bin/docker-credential-desktop.exe</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>也可能是需要修改 <code>~/.docker/config.json</code> 或者 <code>/root/.docker</code> 中的 <code>credsStore</code> 改为 <code>credStore</code></p>
<h3 id="docker-desktop-更新后-container-消失">Docker Desktop 更新后 Container 消失</h3>



  
  

<blockquote class="alert-blockquote alert-error">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Error</span>
  </p>
  <p>Docker-Desktop-Data 没有正确启动，导致 Docker Desktop 在版本更新/电脑重启后，所有的 Container 消失了</p>

</blockquote>
<p>前一阵，<strong>更新 Docker Desktop 版本/重启电脑</strong>后所有的 container 消失了，重启 Docker, WSL2, Windows，均无法将 Container 找回，怀疑是 Docker 更新后没有正确识别迁移的 Docker-Desktop-Data 和 Docker-Desktop 地址导致找不回数据。</p>
<p>此时，首先<strong>不要删除</strong> docker-desktop 版本去做一些版本回退或者其他删除 Docker-Desktop 的行为，这样做会连带将整个 docker-desktop-data 的 <strong>vhdx 挂载盘</strong>也删除，这样会导致部分未 Mount 到 WSL2 的数据无法找回，彻底无法恢复原本 Container 的部分信息。</p>
<p>因此，无论在回退或者重装 docker-desktop 之前，建议做以下的验证：</p>
<ol>
<li>使用 <code>wsl -l -v </code> 查看 Dokcer-Desktop-Data 是否正常启动(状态为 RUNNING)</li>
<li>查找当前 Docker-Desktop 和 Docker-Desktop-Data 当前的挂载位置，是否是安装时迁移出来的位置，可以参考 <a href="https://learn.microsoft.com/zh-cn/windows/wsl/disk-space#how-to-locate-the-vhdx-file-and-disk-path-for-your-linux-distribution" target="_blank" rel="noopener">管理WSL2磁盘空间</a>
 的最后一小节找到 vhdx 的位置；</li>
<li>如果还是原本的位置，参考自己部署服务的 compose file 查看对应位置的文件是否还存在，如果不存在了，可能是被覆盖了，那可能也是没救了；</li>
<li>如果位置和迁移出来的位置不一致，说明是 Docker-Desktop 对应的数据内容位置不对的问题，可以直接按照 WSL2 的步骤重新导入 Docker-Desktop-Data 尝试能不能找回数据；</li>
</ol>
<p>如果数据已经无法恢复，也就只能重新部署服务，需要注意的是，如果是 docker-desktop-data 没有启动的问题，且发现对应的 volume 信息已经没有了，这就说明之前的 container 和 volume 等信息可能是存在临时目录已经找不回了，接下来就是如何正确避免再次发生这种情况。</p>
<p>查阅后发现，这是由于将 Docker-Desktop-Data 的挂载到了别的目录，但是 Docker-Desktop 无法正确识别迁移后的地址，他还会在原本的地址找 Vhdx 文件，如果没找到就会导致 Docker-Desktop-Data 无法和 Docker-Desktop 关联起来，相关的服务也就不会启动。</p>
<p>这里通过 CMD 来建立软连接（<code>mklink {target_path} {file_real_path}</code>）：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 建立软连接（需要再cmd中执行，powershell中可能识别不了mklink命令）</span>
</span></span><span class="line"><span class="cl"><span class="c"># 否则可能会导致 docker-desktop-data 无法正确启动，导致重启后掉盘</span>
</span></span><span class="line"><span class="cl"><span class="n">mklink</span> <span class="s2">&#34;C:\Users\{user-name}\AppData\Local\Docker\wsl\data\ext4.vhdx&#34;</span> <span class="s2">&#34;D:\docker\docker-desktop-data\ext4.vhdx&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>重启 docker-desktop 后再重新部署服务即可，可以简单的部署个别文件后重启检查，部署的时候需要注意</p>
<ul>
<li>如果部署所需的<strong>文件&amp;数据库</strong>都已经 <strong>mount</strong> 到对应的 WSL2 上了，整个重新部署的流程会相对简单一些，而且也不会有信息丢失</li>
<li>部分无法 Mount 的服务建议查看官方文档是否有备份方法，例如 Immich 的用户数据库，需要手动使用脚本进行备份和后续导入，否则虽然照片不会丢失，但是无法和原始账号关联，只能使用曲线救国的方式去重新将旧照片导入新账号。</li>
</ul>
<p>因此对于存储重要用户数据的 Docker 服务，建议是在将数据都 <strong>mount</strong> 出来的同时，做好对应服务器的<strong>容灾备份</strong>，我这里是使用了 kopia 将服务器里重要的数据都做了额外备份，但是还是对 Immich 的数据备份缺失了用户设置的部分。</p>



  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>在部署一个服务的时候，要调查好做服务迁移的时候需要备份和导出的内容, 尽量将数据 mount 到主机上，同时结合 <code>Crontab</code> 和 kopia 等工具去做一个定时的容灾备份，确保自己的重要数据万无一失。</p>

</blockquote>
<h3 id="vmmem-内存和-cpu-占用过高">Vmmem 内存和 CPU 占用过高</h3>
<p>大概率是由于 WSL2 没有限制 docker-desktop 的内存和 CPU 用量导致的，这种时候<strong>重启一下 docker-desktop</strong> 使用率应该就会回到正常值，一劳永逸的话参考一下下面的 [CPU 设置]( #Cpu &amp; Memory Usage Too High) 章节。</p>
<h2 id="basic-information--setting-基础信息和设置">Basic Information &amp; Setting 基础信息和设置</h2>
<h3 id="where-the-volumes-of-container-storage">Where The Volumes of Container Storage</h3>
<p><a href="https://stackoverflow.com/questions/43181654/locating-data-volumes-in-docker-desktop-windows" target="_blank" rel="noopener">Locating data volumes in Docker Desktop (Windows)</a>
: 除了指定了目录的 volume，其他 docker-desktop(WSL2) 的 volume 将会存放在 <code>\\wsl.localhost\docker-desktop-data\data\docker\volumes</code> 中</p>
<h3 id="cpu--memory-usage-too-high">Cpu &amp; Memory Usage Too High</h3>
<p>修改 windows 上 WSL2 的配置文件，限制 docker 对应的 WSL 服务的内存和内核上限，官方的设置文档如下：<a href="https://learn.microsoft.com/zh-tw/windows/wsl/wsl-config#wslconfig" target="_blank" rel="noopener">wslconfig</a>
，其他参考资料 <a href="https://blog.csdn.net/qq_31745863/article/details/129852886" target="_blank" rel="noopener">CSDN</a>
</p>
<p>配置文件的地址为：<code>c:\user\{your name}\.wslconfig</code> ，如果没有该文件就手动创建一个，可以仅仅简单的配置如下项目即可，具体的数值参考自己电脑的配置，更多配置项可以参考官方文档：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>.config</span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code class="language-.config" data-lang=".config">[wsl2]
# 核心数配置
processors=8
memory=8GB</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>保存后用如下命令关闭 WSL 并重启docker即可</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">wsl</span> <span class="p">-</span><span class="n">-shutdown</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script>]]></content:encoded>
    </item>
    <item>
      <title>LearnWeb21-JS06-异步JS</title>
      <link>https://aikenh.cn/posts/learnweb21-js06-%E5%BC%82%E6%AD%A5js/</link>
      <pubDate>Wed, 01 May 2024 06:22:33 +0000</pubDate>
      <guid>https://aikenh.cn/posts/learnweb21-js06-%E5%BC%82%E6%AD%A5js/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-summary&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Summary&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;如果页面的功能较为复杂，且涉及到了从服务端获取数据等操作，如果简单的使用同步编程，等待一个个任务按顺序执行，由于网络或者某些时间复杂度较高的操作，导致网页加载时间过长，或者使用逻辑不合理（加载某些资源的同时无法进行浏览等），因此异步编程的特性在 web 端是十分重要的。&lt;/p&gt;

&lt;/blockquote&gt;
&lt;p&gt;通过&lt;strong&gt;异步编程&lt;/strong&gt;使一个长时间运行的任务运行的同时能够对网页做出其他的操作和对其他事件做出相应，而不需等待该任务完成，以下的这些功能就是最常见需要异步完成的；&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;fetch&lt;/code&gt; 发起 http 请求&lt;/li&gt;
&lt;li&gt;&lt;code&gt;getUserMedia()&lt;/code&gt; 获取用户的摄像头和麦克风&lt;/li&gt;
&lt;li&gt;&lt;code&gt;showOpenFilePicker()&lt;/code&gt; 请求用户选择文件以供访问。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;基于事件处理程序实现异步&#34;&gt;基于事件处理程序实现异步&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;事件处理的逻辑实际上也是一种接近异步编程的方式，对应的函数不是即时执行，而是等事件被触发后在进行调用。一些早期的异步 API 就是这样使用事件的。&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>如果页面的功能较为复杂，且涉及到了从服务端获取数据等操作，如果简单的使用同步编程，等待一个个任务按顺序执行，由于网络或者某些时间复杂度较高的操作，导致网页加载时间过长，或者使用逻辑不合理（加载某些资源的同时无法进行浏览等），因此异步编程的特性在 web 端是十分重要的。</p>

</blockquote>
<p>通过<strong>异步编程</strong>使一个长时间运行的任务运行的同时能够对网页做出其他的操作和对其他事件做出相应，而不需等待该任务完成，以下的这些功能就是最常见需要异步完成的；</p>
<ul>
<li><code>fetch</code> 发起 http 请求</li>
<li><code>getUserMedia()</code> 获取用户的摄像头和麦克风</li>
<li><code>showOpenFilePicker()</code> 请求用户选择文件以供访问。</li>
</ul>
<h2 id="基于事件处理程序实现异步">基于事件处理程序实现异步</h2>
<blockquote>
<p>事件处理的逻辑实际上也是一种接近异步编程的方式，对应的函数不是即时执行，而是等事件被触发后在进行调用。一些早期的异步 API 就是这样使用事件的。</p>
</blockquote>
<p>一些早期的异步 API 就是这样来使用事件，例如 <code>XMLHttpRequest</code> 可以使用 JS 向远程服务器发起 HTTP 请求，这类网络请求操作都会比较耗时，因此通常会使用异步，以下面的例子进行后续说明；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">log</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;.event-log&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;#xhr&#34;</span><span class="p">).</span><span class="nx">addEventListener</span><span class="err">）</span><span class="p">(</span><span class="s2">&#34;click&#34;</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">log</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kr">const</span> <span class="nx">xhr</span>  <span class="o">=</span> <span class="k">new</span> <span class="nx">XMLHttpRequest</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">	<span class="nx">xhr</span><span class="p">.</span><span class="nx">addEvenetLister</span><span class="p">(</span><span class="s2">&#34;loadend&#34;</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">log</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="sb">`</span><span class="si">${</span><span class="nx">log</span><span class="p">.</span><span class="nx">textContent</span><span class="si">}</span><span class="sb"> 完成, 状态码: </span><span class="si">${</span><span class="nx">xhr</span><span class="p">.</span><span class="nx">status</span><span class="si">}</span><span class="sb">`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">});</span>
</span></span><span class="line"><span class="cl">	<span class="nx">xhr</span><span class="p">.</span><span class="nx">open</span><span class="p">(</span><span class="s2">&#34;GET&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="s2">&#34;https://URL/dir/file.json&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="nx">xhr</span><span class="p">.</span><span class="nx">send</span><span class="p">()</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">	<span class="nx">log</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="sb">`</span><span class="si">${</span><span class="nx">log</span><span class="p">.</span><span class="nx">textContent</span><span class="si">}</span><span class="sb"> 请求已发起\n`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><code>xhr</code> 按钮点击后，声明一个 <code>XMLHttpRequest</code> 对象，并监听其 <code>loadend</code> 事件，然后发送请求，并将字符串修改为请求已发起，该字符串会在触发了 <code>loadend</code> 加载完了请求事件后改为，已完成。</p>
<blockquote>
<p>事件处理程序本身是一种特殊类型的回调函数（函数作为参数传递到另一个函数），多层回调函数的嵌套会导致代码难以理解和 debug，因此后面大多数 API 不在使用回调函数去处理异步的情况。</p>
</blockquote>
<h2 id="promise-现代-js-异步编程的基础">Promise 现代 JS 异步编程的基础</h2>
<blockquote>
<p><strong>Promise</strong> 是现代 JavaScript 中异步编程的基础。它是一个由异步函数返回的对象，可以指示操作当前所处的状态。在 Promise 返回给调用者的时候，操作往往还没有完成，但 Promise 对象提供了方法来处理操作最终的成功或失败。</p>
</blockquote>
<p>一个基于 <code>Promise</code> 的 API，异步函数会启动操作并直接返回一个 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise" target="_blank" rel="noopener"><code>Promise</code></a>
 对象，可以将后续的处理函数附加到该对象上，当操作完成时（成功、失败），执行对应的处理函数。</p>
<h3 id="以-fetch-为例">以 fetch() 为例</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">fetchPromise</span> <span class="o">=</span> <span class="nx">fetch</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">	<span class="s2">&#34;https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">fetchPromise</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">fetchPromise</span><span class="p">.</span><span class="nx">then</span><span class="p">((</span><span class="nx">response</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`已受到响应 </span><span class="si">${</span><span class="nx">response</span><span class="p">.</span><span class="nx">status</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;已发送请求...&#34;</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>console</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="go">Promise { &lt;state&gt;: &#34;pending&#34;}
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol>
<li>调用 <code>fetch()</code> 将返回的 <code>promise</code> 存储到 <code>fetchPromise</code> 变量</li>
<li><code>Promise</code> 的变量输出结果如下</li>
<li>将处理函数传递给 promise 变量的 then 函数，当 fetch 操作成功的时候，promise 就会调用对应的处理函数。</li>
</ol>
<p>整体的处理逻辑还是比较清晰的，关键是使用 promise 变量的 then 函数去处理 fetch 的各种不同结果。</p>
<h3 id="链式使用-promise">链式使用 Promise</h3>
<p>在前面通过 fetch 获取 response 对象的时候，我们需要使用对应的 <code>json()</code> 方法将其转换为 js 专属的对象，这里的 json 实际上也是一个异步方法，由此我们可以链式的实现异步如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">fetchPromise</span> <span class="o">=</span> <span class="nx">fetch</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">	<span class="s2">&#34;https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">fetchPromisze</span><span class="p">.</span><span class="nx">then</span><span class="p">((</span><span class="nx">response</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="kr">const</span> <span class="nx">jsonPromise</span> <span class="o">=</span> <span class="nx">response</span><span class="p">.</span><span class="nx">json</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">	<span class="nx">jsonPromise</span><span class="p">.</span><span class="nx">then</span><span class="p">((</span><span class="nx">json</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">json</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这种情况在多层嵌套的时候也会堆叠得很难理解，但是相比于回调函数，每一级的回调都会有个 promise 的<strong>即时返回值</strong>来指示对应异步函数中的完成状态。</p>
<p>由于 <code>promise</code> 是一个<strong>即时返回值</strong>，因此上述的代码可以简写为：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">fetchPromise</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">then</span><span class="p">((</span><span class="nx">response</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">response</span><span class="p">.</span><span class="nx">json</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">then</span><span class="p">((</span><span class="nx">data</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">data</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">});</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>不必在第一个 then 中调用下一个 then，可以直接返回对应的 promise 对象，对对应的 promise 对象调用处理即可，这样可以避免多级缩进叠加；</p>
<h3 id="处理异常返回值">处理异常返回值</h3>
<p>对 <code>promise</code> 中的状态值进行检查，如果状态码不是 ok 就需要对应的抛出错误：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">fetchPromise</span> <span class="o">=</span> <span class="nx">fetch</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">	<span class="s2">&#34;https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">fetchPromise</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">then</span><span class="p">((</span><span class="nx">response</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">response</span><span class="p">.</span><span class="nx">ok</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">			<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="sb">`HTTP 请求错误 </span><span class="si">${</span><span class="nx">response</span><span class="p">.</span><span class="nx">status</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="p">})</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nx">then</span><span class="p">((</span><span class="nx">json</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">json</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">});</span>
</span></span><span class="line"><span class="cl">	
</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>此外由于这种异步的函数返回机制，如果要按照上面的方式逐个进行错误处理非常的困难，需要在每个嵌套层中进行处理，为了避免这种麻烦，Promise 对象提供了一个 <code>catch()</code> 方法（类似 then），当调用成功时触发的是 <code>then</code> 而调用失败了就会调用 <code>catch</code> 中定义的处理函数。</p>
<p>将 <code>catch</code> 添加到 <code>Promise</code> 的末尾，他可以在任何异步函数失败的时候调用，下面是一个例子：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">fetchPromise</span> <span class="o">=</span> <span class="nx">fetch</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;bad-scheme://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">fetchPromise</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">then</span><span class="p">((</span><span class="nx">response</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">response</span><span class="p">.</span><span class="nx">ok</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="sb">`HTTP 请求错误：</span><span class="si">${</span><span class="nx">response</span><span class="p">.</span><span class="nx">status</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">response</span><span class="p">.</span><span class="nx">json</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="p">})</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">then</span><span class="p">((</span><span class="nx">json</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">json</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">})</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="k">catch</span><span class="p">((</span><span class="nx">error</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="sb">`无法获取产品列表：</span><span class="si">${</span><span class="nx">error</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="promise-的状态值">Promise 的状态值</h3>
<blockquote>
<p>需要注意 <code>promise</code> 对应的成功和失败的含义随着 API 的不同而不同，例如 <code>fetch</code> 认为服务器返回一个错误如（404 not found）时请求成功，但如果网络错误阻止请求被发送，则认为请求失败。</p>
</blockquote>
<table>
  <thead>
      <tr>
          <th style="text-align: left">Status</th>
          <th style="text-align: center">Desc</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: left">Pending 待定</td>
          <td style="text-align: center">还在请求中，尚未有确定的结果，也是初始状态</td>
      </tr>
      <tr>
          <td style="text-align: left">fulfilled 已兑现</td>
          <td style="text-align: center">操作成功的标准返回，后续进入调用 then 的逻辑</td>
      </tr>
      <tr>
          <td style="text-align: left">rejected 已拒绝</td>
          <td style="text-align: center">操作失败的标准返回，后续进入调用 catch 的逻辑</td>
      </tr>
  </tbody>
</table>
<p>有时用**已敲定(settled)<strong>来同时表示已兑现和已拒绝；如果一个 Promise 已敲定，或者他被&quot;锁定&quot;以跟踪另一个 Promise 的状态，那么就是</strong>已解决(resolved)**的。</p>
<h3 id="组式使用-promise-合并使用">组式使用 Promise (合并使用)</h3>
<blockquote>
<p>当操作由多个异步函数组成，如果需要串行完成那就需要 promise 链，如果需要组合使用多个 promise，相互之间不依赖但是需要所有 promise 都实现的情况，可以考虑合并多个异步函数的使用。</p>
</blockquote>
<p>使用 <code>Promise.all()</code> 接受一个 <code>Promise</code> 数组，并返回一个单一的 <code>Promise</code>，使用该操作通过合并来简化对一批 <code>promise</code> 的处理，由 <code>promise.all()</code> 返回的 <code>promise</code> 有以下的特性：</p>
<ul>
<li>什么时候调用 then？当数组中所有 promise 都兑现时;</li>
<li>传入 then 的形式式什么？提供一个包含所有响应的数组，顺序与传入 all 的顺序一致;</li>
<li>什么时候拒绝/调用catch？任何一个promise 没有兑现的时候，调用 <code>catch</code>，并提供被拒绝的 promise 抛出的错误;</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">fetchPromise1</span> <span class="o">=</span> <span class="nx">fetch</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">fetchPromise2</span> <span class="o">=</span> <span class="nx">fetch</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/not-found&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">fetchPromise3</span> <span class="o">=</span> <span class="nx">fetch</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">//const fetchPromise3 = fetch(
</span></span></span><span class="line"><span class="cl"><span class="c1">//  &#34;bad-scheme://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json&#34;,
</span></span></span><span class="line"><span class="cl"><span class="c1">//);
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nb">Promise</span><span class="p">.</span><span class="nx">all</span><span class="p">([</span><span class="nx">fetchPromise1</span><span class="p">,</span> <span class="nx">fetchPromise2</span><span class="p">,</span> <span class="nx">fetchPromise3</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">then</span><span class="p">((</span><span class="nx">responses</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kr">const</span> <span class="nx">response</span> <span class="k">of</span> <span class="nx">responses</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`</span><span class="si">${</span><span class="nx">response</span><span class="p">.</span><span class="nx">url</span><span class="si">}</span><span class="sb">：</span><span class="si">${</span><span class="nx">response</span><span class="p">.</span><span class="nx">status</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">})</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="k">catch</span><span class="p">((</span><span class="nx">error</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="sb">`获取失败：</span><span class="si">${</span><span class="nx">error</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="选择使用-promise-任一">选择使用 Promise (任一)</h3>
<p>如果需要一组Promise 中某一个实现即可，这种时候可以使用 <code>promise.any()</code>, 任意一个被兑现时便兑现，仅当所有 Promise 被拒绝的时候才拒绝。</p>
<h2 id="async-和-await">async 和 await</h2>
<p>在函数的开头添加 <code>async</code> 关键词可以使得一个函数成为一个异步函数：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">async</span> <span class="kd">function</span> <span class="nx">myFunction</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">	<span class="p">...</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><code>await</code> 关键词则使得我们不再并行执行异步函数，而是在原地等待该异步函数执行完成，也就是讲异步函数当成同步函数来使用，直到其 Promise 相应彻底完成，如下可以将 fetch 改写成同步函数：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">async</span> <span class="kd">function</span> <span class="nx">fetchProducts</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 在这一行之后，我们的函数将等待 `fetch()` 调用完成
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">// 调用 `fetch()` 将返回一个“响应”或抛出一个错误
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kr">const</span> <span class="nx">response</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetch</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">response</span><span class="p">.</span><span class="nx">ok</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="sb">`HTTP 请求错误：</span><span class="si">${</span><span class="nx">response</span><span class="p">.</span><span class="nx">status</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 在这一行之后，我们的函数将等待 `response.json()` 的调用完成
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">// `response.json()` 调用将返回 JSON 对象或抛出一个错误
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kr">const</span> <span class="nx">json</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">response</span><span class="p">.</span><span class="nx">json</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">json</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="sb">`无法获取产品列表：</span><span class="si">${</span><span class="nx">error</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">fetchProducts</span><span class="p">();</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这个 <code>fetchProducts()</code> 还是一个异步函数，因此不能按照以下的方法调用：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">promise</span> <span class="o">=</span> <span class="nx">fetchProducts</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">promise</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">name</span><span class="p">);</span> <span class="c1">// “promise”是一个 Promise 对象，因此这句代码无法正常工作
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>相反的，需要按照 promise 的方式去调用：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">promise</span> <span class="o">=</span> <span class="nx">fetchProducts</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">promise</span><span class="p">.</span><span class="nx">then</span><span class="p">((</span><span class="nx">data</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">data</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">name</span><span class="p">));</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>同样地，请注意你只能在 <code>async</code> 函数中使用 <code>await</code>，除非你的代码是 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Modules" target="_blank" rel="noopener">JavaScript 模块</a>
。这意味着你不能在普通脚本中这样做：</p>
<p>你可能会在需要使用 Promise 链地方使用 <code>async</code> 函数，这也使得 Promise 的工作更加直观。</p>
<p>请记住，就像一个 Promise 链一样，<code>await</code> 强制异步操作以串联的方式完成。如果下一个操作的结果取决于上一个操作的结果，这是必要的，但如果不是这样，像 <code>Promise.all()</code> 这样的操作会有更好的性能。</p>
<h2 id="promise-实战">Promise 实战</h2>
<blockquote>
<p>前面讨论<strong>如何使用返回</strong> promise 的 APIs，这一节研究<strong>如何实现返回</strong> Promise 的 Apis，这与基于使用 promise 的 APIs 相比，是一个不太常见的任务。参考文献 <a href="https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Asynchronous/Implementing_a_promise-based_API" target="_blank" rel="noopener">mdn如何实现基于promise的api</a>
 | <a href="https://www.runoob.com/js/js-promise.html" target="_blank" rel="noopener">菜鸟教程JavaScript Promise</a>
 | <a href="https://www.liaoxuefeng.com/wiki/1022910821149312/1023024413276544" target="_blank" rel="noopener">廖雪峰JavaScript</a>
</p>
</blockquote>
<p>以一个普通的回调转换为 Promise 的例子来说明：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">output</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;#output&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">button</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;#set-alarm&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">setAlarm</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nb">window</span><span class="p">.</span><span class="nx">setTimeout</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">output</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="s2">&#34;Wake up!&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span> <span class="mi">1000</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">button</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;click&#34;</span><span class="p">,</span> <span class="nx">setAlarm</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>利用 Promise 来构造后会变成如下的实现：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">alarm</span><span class="p">(</span><span class="nx">person</span><span class="p">,</span> <span class="nx">delay</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="k">new</span> <span class="nb">Promise</span><span class="p">((</span><span class="nx">resolve</span><span class="p">,</span> <span class="nx">reject</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">delay</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s2">&#34;Alarm delay must not be negative&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="nb">window</span><span class="p">.</span><span class="nx">setTimeout</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">resolve</span><span class="p">(</span><span class="sb">`Wake up, </span><span class="si">${</span><span class="nx">person</span><span class="si">}</span><span class="sb">!`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span> <span class="nx">delay</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>该函数会创建并返回一个新的 Promise，其中需要说明的是，Promise 本身需要两个参数 resolve 和 reject，当执行成功了就会调用 resolve（类似 return），如果失败了，就会自动调用 reject，（throw error 的部分），两者都可以讲任何类型的单个参数传递，具体而言参考后续调用如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">button</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;click&#34;</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">alarm</span><span class="p">(</span><span class="nx">name</span><span class="p">.</span><span class="nx">value</span><span class="p">,</span> <span class="nx">delay</span><span class="p">.</span><span class="nx">value</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">then</span><span class="p">((</span><span class="nx">message</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">(</span><span class="nx">output</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="nx">message</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="k">catch</span><span class="p">((</span><span class="nx">error</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">(</span><span class="nx">output</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="sb">`Couldn&#39;t set alarm: </span><span class="si">${</span><span class="nx">error</span><span class="si">}</span><span class="sb">`</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以讲一个函数变成具备原生异步功能的 Promise？由此我们就可以对其使用 await 或者 async 来灵活的决定该 Function 要同步或者异步执行。</p>
<h2 id="workers-页面线程简介">Workers 页面线程简介</h2>



  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p><a href="https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Asynchronous/Introducing_workers" target="_blank" rel="noopener">Worker</a>
使页面能在单独执行的线程中运行一些任务，避免因为一个长期运行的同步任务使整个任务完全没有响应。</p>

</blockquote>
<p>一些多线程的 Principle，避免同时访问相同的变量带来的意外等：</p>
<ul>
<li>主代码和你的 worker 代码永远不能直接访问彼此的变量</li>
<li>Workers 和主代码运行在完全分离的环境中，只有通过相互发送消息来进行交互</li>
<li>这意味着 workers 不能访问 DOM（窗口、文档、页面元素等等）</li>
</ul>
<p>有三种不同类型的 workers，不过该章节只会介绍第一个，其他两个简要的讨论。</p>
<ul>
<li>dedicated workers</li>
<li>shared workers</li>
<li>service workers</li>
</ul>
<p>以页面中的质数生成器为例，如果作为同步任务执行，在计算过程中整个页面将会卡住，按照以下的方式来讲计算交付于另一个 worker。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="c1">// 在 &#34;generate.js&#34; 中创建一个新的 worker
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">const</span> <span class="nx">worker</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Worker</span><span class="p">(</span><span class="s2">&#34;./generate.js&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 当用户点击 &#34;Generate primes&#34; 时，给 worker 发送一条消息。
</span></span></span><span class="line"><span class="cl"><span class="c1">// 消息中的 command 属性是 &#34;generate&#34;, 还包含另外一个属性 &#34;quota&#34;，即要生成的质数。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;#generate&#34;</span><span class="p">).</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;click&#34;</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">quota</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;#quota&#34;</span><span class="p">).</span><span class="nx">value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">worker</span><span class="p">.</span><span class="nx">postMessage</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="nx">command</span><span class="o">:</span> <span class="s2">&#34;generate&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">quota</span><span class="o">:</span> <span class="nx">quota</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 当 worker 给主线程回发一条消息时，为用户更新 output 框，包含生成的质数（从 message 中获取）。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">worker</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;message&#34;</span><span class="p">,</span> <span class="p">(</span><span class="nx">message</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;#output&#34;</span><span class="p">).</span><span class="nx">textContent</span> <span class="o">=</span>
</span></span><span class="line"><span class="cl">    <span class="sb">`Finished generating </span><span class="si">${</span><span class="nx">message</span><span class="p">.</span><span class="nx">data</span><span class="si">}</span><span class="sb"> primes!`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;#reload&#34;</span><span class="p">).</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;click&#34;</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;#user-input&#34;</span><span class="p">).</span><span class="nx">value</span> <span class="o">=</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;Try typing in here immediately after pressing &#34;Generate primes&#34;&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nb">document</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">reload</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>通过 worker.postMessage 来和对应的线程传递信息，在对应的 worker 中，可以按照以下的方式来接受和传递信息；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="c1">// 监听主线程中的消息。
</span></span></span><span class="line"><span class="cl"><span class="c1">// 如果消息中的 command 是 &#34;generate&#34;，则调用 `generatePrimse()`
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;message&#34;</span><span class="p">,</span> <span class="p">(</span><span class="nx">message</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">message</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">command</span> <span class="o">===</span> <span class="s2">&#34;generate&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">generatePrimes</span><span class="p">(</span><span class="nx">message</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">quota</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 生成质数 (非常低效)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">function</span> <span class="nx">generatePrimes</span><span class="p">(</span><span class="nx">quota</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kd">function</span> <span class="nx">isPrime</span><span class="p">(</span><span class="nx">n</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">c</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="nx">c</span> <span class="o">&lt;=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">sqrt</span><span class="p">(</span><span class="nx">n</span><span class="p">);</span> <span class="o">++</span><span class="nx">c</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="nx">n</span> <span class="o">%</span> <span class="nx">c</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">primes</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">maximum</span> <span class="o">=</span> <span class="mi">1000000</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">while</span> <span class="p">(</span><span class="nx">primes</span><span class="p">.</span><span class="nx">length</span> <span class="o">&lt;</span> <span class="nx">quota</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">candidate</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">random</span><span class="p">()</span> <span class="o">*</span> <span class="p">(</span><span class="nx">maximum</span> <span class="o">+</span> <span class="mi">1</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">isPrime</span><span class="p">(</span><span class="nx">candidate</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">primes</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">candidate</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// 完成后给主线程发送一条包含我们生成的质数数量的消息消息。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">postMessage</span><span class="p">(</span><span class="nx">primes</span><span class="p">.</span><span class="nx">length</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>worker 要做的第一件事情就是开始监听来自主脚本的消息。这通过使用 <code>addEventListener()</code> 实现，它在 worker 中是一个全局函数。在 <code>message</code> 事件处理器内部，事件的 <code>data</code> 属性包含一个来自主脚本的参数的副本。</p>



  
  

<blockquote class="alert-blockquote alert-note">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Note</span>
  </p>
  <p>**备注：**要运行此站点，你必须运行一个本地 web 服务器，因为 file:// URLs 不允许加载 workers。参考我们的<a href="https://developer.mozilla.org/zh-CN/docs/Learn/Common_questions/Tools_and_setup/set_up_a_local_testing_server" target="_blank" rel="noopener">设置一个本地测试服务器</a>
的指导。完成后，你应该可以点击 &ldquo;Generate primes&rdquo; 并且使你的主页面保持响应。 如果你在创建和运行这个样例的过程中有疑问，你可以在 <a href="https://github.com/mdn/learning-area/blob/main/javascript/asynchronous/workers/finished" target="_blank" rel="noopener">https://github.com/mdn/learning-area/blob/main/javascript/asynchronous/workers/finished</a>
 查看完成后的版本，并且在 <a href="https://mdn.github.io/learning-area/javascript/asynchronous/workers/finished" target="_blank" rel="noopener">https://mdn.github.io/learning-area/javascript/asynchronous/workers/finished</a>
 进行在线尝试。</p>

</blockquote>
<p>我们刚刚创建的 worker 被称为 <em>dedicated worker</em>。这意味着它由一个脚本实例使用。</p>
<p>不过，还有其他类型的 worker：</p>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/SharedWorker" target="_blank" rel="noopener"><code>SharedWorker</code></a>
 可以由运行在不同窗口中的多个不同脚本共享。</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Service_Worker_API" target="_blank" rel="noopener"><em>Service worker</em></a>
 的行为就像代理服务器，缓存资源以便于 web 应用程序可以在用户离线时工作。他们是<a href="https://developer.mozilla.org/zh-CN/docs/Web/Progressive_web_apps" target="_blank" rel="noopener">渐进式 Web 应用</a>
的关键组件。</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>LearnWeb20-JS05-JSON使用</title>
      <link>https://aikenh.cn/posts/learnweb20-js05-json%E4%BD%BF%E7%94%A8/</link>
      <pubDate>Tue, 30 Apr 2024 14:44:51 +0000</pubDate>
      <guid>https://aikenh.cn/posts/learnweb20-js05-json%E4%BD%BF%E7%94%A8/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-summary&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Summary&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;本篇是 &lt;a href=&#34;https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/JSON&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Mdn 使用 JSON&lt;/a&gt;
 一文的阅读笔记，对 web 开发中的 JSON 进行了介绍&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>本篇是 <a href="https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/JSON" target="_blank" rel="noopener">Mdn 使用 JSON</a>
 一文的阅读笔记，对 web 开发中的 JSON 进行了介绍</p>

</blockquote>
<h2 id="json-简介">JSON 简介</h2>
<p>JavaScript Object Notation(JSON)是将结构化数据表示为 JavaScript 对象的标准格式，通常用于网页上的表示和传输数据（服务端，客户端），熟悉 JSON 对象的创建，传输，解析，对于 JS 来说也是一门基本功了。</p>
<p>JSON 可以存在单独的文件中，后缀为 <code>.json</code>，同时在进行网络传输时，<a href="https://developer.mozilla.org/zh-CN/docs/Glossary/MIME_type" target="_blank" rel="noopener">MIME 类型</a>
为 <code>application/json</code></p>
<h3 id="基本操作介绍">基本操作介绍</h3>
<p>对 JSON 这类标记语言进行的操作通常就是下面的两种：</p>
<ul>
<li>将字符串转换为原生对象的过程称为反序列化(deserialization)</li>
<li>将原生对象转换为字符串进行网络传输的字符串的过程则成为序列化(serialization)</li>
</ul>
<p>因此可以理解为这就是一个 object-string 的相互转换过程，因此在一个语言中如何使用 json 这种标记语言，最核心的就是上述的这两个操作，随着后续的发展，JSON 在除了 js 的其他语言中也被广泛的使用到。</p>
<h3 id="json-结构和语法">JSON 结构和“语法”</h3>
<p>整个 JSON 是一个字符串，其非常类似于 JS 对象字面量的写法（无需命名对象名），且其中<strong>仅包含要传输的数据（属性）而不包含方法</strong>；</p>
<p>一般而言有两种方法来编写 JSON 文件，一种是类似对象字面量（字典），存储一个单体对象的方式；另一种则是 JSON 数组，最外层用数组的形式，在数组里面可以存储多个单独对象。下面分别给出示例：</p>
<p><strong>单对象形式</strong>，对象字面量（like 字典），js 中反序列化获取之后就会得到一个对象，使用对象的方法去调用其中的属性即可。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>json</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&#34;squadName&#34;</span><span class="p">:</span> <span class="s2">&#34;Super hero squad&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> 	<span class="nt">&#34;homeTown&#34;</span><span class="p">:</span> <span class="s2">&#34;Metro City&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> 	<span class="nt">&#34;formed&#34;</span><span class="p">:</span> <span class="mi">2016</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> 	<span class="nt">&#34;menbers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">	 	<span class="p">{</span>
</span></span><span class="line"><span class="cl">	 		<span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;Molecule Man&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	      	<span class="nt">&#34;age&#34;</span><span class="p">:</span> <span class="mi">29</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	      	<span class="nt">&#34;secretIdentity&#34;</span><span class="p">:</span> <span class="s2">&#34;Dan Jukes&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	      	<span class="nt">&#34;powers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">	      		<span class="s2">&#34;Radiation resistance&#34;</span><span class="p">,</span> <span class="s2">&#34;Turning tiny&#34;</span><span class="p">,</span> <span class="s2">&#34;Radiation blast&#34;</span>
</span></span><span class="line"><span class="cl">	      	<span class="p">]</span>
</span></span><span class="line"><span class="cl">	 	<span class="p">},</span>
</span></span><span class="line"><span class="cl">	 	<span class="p">{</span>
</span></span><span class="line"><span class="cl">	 		<span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;Madame Uppercut&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	   		<span class="nt">&#34;age&#34;</span><span class="p">:</span> <span class="mi">39</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	   		<span class="nt">&#34;secretIdentity&#34;</span><span class="p">:</span> <span class="s2">&#34;Jane Wilson&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	   		<span class="nt">&#34;powers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">	     		<span class="s2">&#34;Million tonne punch&#34;</span><span class="p">,</span><span class="s2">&#34;Damage resistance&#34;</span><span class="p">,</span> <span class="s2">&#34;Superhuman reflexes&#34;</span>
</span></span><span class="line"><span class="cl">	  		<span class="p">]</span>
</span></span><span class="line"><span class="cl">	 	<span class="p">}</span>
</span></span><span class="line"><span class="cl"> 	<span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>数组多对象形式</strong>,下面这种写法也是一种合法的 JSON，js 中反序列化获取后则会得到一个数组对象，使用下标去索引即可。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>json</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">[</span>
</span></span><span class="line"><span class="cl">	<span class="p">{</span>
</span></span><span class="line"><span class="cl">	   <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;Molecule Man&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	   <span class="nt">&#34;age&#34;</span><span class="p">:</span> <span class="mi">29</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	   <span class="nt">&#34;secretIdentity&#34;</span><span class="p">:</span> <span class="s2">&#34;Dan Jukes&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	   <span class="nt">&#34;powers&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;Radiation resistance&#34;</span><span class="p">,</span> <span class="s2">&#34;Turning tiny&#34;</span><span class="p">,</span> <span class="s2">&#34;Radiation blast&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">	 <span class="p">},</span>
</span></span><span class="line"><span class="cl">	 <span class="p">{</span>
</span></span><span class="line"><span class="cl">	   <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;Madame Uppercut&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	   <span class="nt">&#34;age&#34;</span><span class="p">:</span> <span class="mi">39</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	   <span class="nt">&#34;secretIdentity&#34;</span><span class="p">:</span> <span class="s2">&#34;Jane Wilson&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	   <span class="nt">&#34;powers&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">	     <span class="s2">&#34;Million tonne punch&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	     <span class="s2">&#34;Damage resistance&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	     <span class="s2">&#34;Superhuman reflexes&#34;</span>
</span></span><span class="line"><span class="cl">	   <span class="p">]</span>
</span></span><span class="line"><span class="cl">	 <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>同时 JSON 还有以下的一些编写规范：</p>
<ol>
<li>纯数据，只包含属性不包含方法；</li>
<li>要求字符串和属性名称使用双引号，单引号无效；</li>
<li>错位的 <code>,</code> 和 <code>;</code> 都可能导致 json 文件出错，要做好检查，可以使用<a href="https://jsonlint.com/" target="_blank" rel="noopener">JSONLint</a>
  这样的程序来验证；</li>
<li>JSON 实际上可以使任何可以有效包含在 JSON 中的数据类型的形式，例如，单个字符串或者单个数字也是一个有效的 JSON 对象；</li>
</ol>
<h2 id="序列化反序列化">序列化&amp;反序列化</h2>
<blockquote>
<p>由于序列化和反序列化的操作在 web 环境中的普遍性，因此浏览器都有一个内建的 api <code>JSON</code> 来支持这些操作，主要是下面的两个方法</p>
<ul>
<li><code>parse(string)</code> 以字符串形式接收 JSON 对象，并返回 js 的内建对象。</li>
<li><code>stringify(obj)</code> 以对象作为参数，返回对应的 JSON 字符串。</li>
</ul>
</blockquote>
<h3 id="deserialization-反序列化">Deserialization 反序列化</h3>
<p>获取 JSON 数据进行<strong>反序列化</strong>通常会有两种情况：传输格式为 JSON 是已知 &amp;&amp; 接收到字符串，需要将其按照 JSON 的方式转换为对象；</p>
<p>第一种情况下可以直接使用 <code>response.json()</code> 直接将获取到的数据转换为对象：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">superHeros</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">response</span><span class="p">.</span><span class="nx">json</span><span class="p">();</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>第二种情况下使用浏览器的 <code>JSON</code> api 来实现转换：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">superHeros</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">superHerostext</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="serialization-序列化">Serialization 序列化</h3>
<p>和反序列化正好相反，序列化也很简单，使用下面 <code>stringify()</code> 方法：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">myObj</span> <span class="o">=</span> <span class="p">{</span><span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;aikenhong&#34;</span><span class="p">,</span> <span class="nx">age</span><span class="o">:</span> <span class="s2">&#34;26&#34;</span><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">myString</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">myObj</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">myString</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以将上述代码在控制台输入试试，序列化后就可以进行数据传输</p>
<h2 id="数据传输">数据传输</h2>
<h3 id="process-with-fetch-date">Process with Fetch Date</h3>
<blockquote>
<p>序列化和反序列化过程避不开数据的获取和传输，因此这里会简单介绍一下 JSON 数据的获取和传输的方法。</p>
</blockquote>
<p>这一部分给出一个典型的获取函数来进行说明整个数据获取流程的组成。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">async</span> <span class="kd">function</span> <span class="nx">getJsonData</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">	<span class="kr">const</span> <span class="nx">requestURL</span> <span class="o">=</span> 
</span></span><span class="line"><span class="cl">		<span class="s2">&#34;https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kr">const</span> <span class="nx">request</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Request</span><span class="p">(</span><span class="nx">requestURL</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="kr">const</span> <span class="nx">response</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetch</span><span class="p">(</span><span class="nx">request</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="kr">const</span> <span class="nx">superHeros</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">response</span><span class="p">.</span><span class="nx">json</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">	
</span></span><span class="line"><span class="cl">	<span class="c1">// deserialization2 example.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// const superHerosText = await response.text();
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// const superHeros = JSON.parse(superHerosText);
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">	<span class="nx">methodUseObjReceived</span><span class="p">(</span><span class="nx">superHeros</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol>
<li>通过 <code>requestURL</code> 初始化一个新的 <code>Request</code> 对象（一个请求体）；</li>
<li>使用 <code>fetch()</code> 方法对这个 <code>Request</code> 对象发起请求，返回一个 <code>response</code> 对象；</li>
<li>使用 <code>response</code> 对象的 <code>json()</code> 以 JSON 的方式获取内容并返回对应的对象；</li>
</ol>
<blockquote>
<p>fetch() API 是异步的，这个再后续的章节中会介绍异步函数的知识，目前仅需知道，调用了异步 api 的函数名称前要加入 <code>async</code> 关键字，并在异步 api 的调用之前添加 <code>await</code> 关键字。</p>
</blockquote>
<h3 id="reference">Reference</h3>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API" target="_blank" rel="noopener">FetchAPI</a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch" target="_blank" rel="noopener">使用Fetch</a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods" target="_blank" rel="noopener">HTTP请求方法</a>
</li>
<li><a href="https://www.json.org/json-zh.html" target="_blank" rel="noopener">JSON官网</a>
</li>
</ul>
<p>上面这些资料有一些现在就可以看看，有一些在对相关知识了解的更全面之后可以进一步的学习一下。</p>
]]></content:encoded>
    </item>
    <item>
      <title>LearnWeb19-JS04-类与对象</title>
      <link>https://aikenh.cn/posts/learnweb19-js04-%E7%B1%BB%E4%B8%8E%E5%AF%B9%E8%B1%A1/</link>
      <pubDate>Sun, 28 Apr 2024 16:46:21 +0000</pubDate>
      <guid>https://aikenh.cn/posts/learnweb19-js04-%E7%B1%BB%E4%B8%8E%E5%AF%B9%E8%B1%A1/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-summary&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Summary&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;JS 中的一切变量皆为对象，可以将对象理解为一个包含相关数据和方法的集合（变量 &amp;amp; 函数）我们也将其称之为属性和方法，就像我们在 python 里做的那样，本篇为 &lt;a href=&#34;https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/Basics&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;mdn_JS对象基础&lt;/a&gt;
，&lt;a href=&#34;https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/Object_prototypes&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;mdn_JS对象原型&lt;/a&gt;
 的阅读笔记&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>JS 中的一切变量皆为对象，可以将对象理解为一个包含相关数据和方法的集合（变量 &amp; 函数）我们也将其称之为属性和方法，就像我们在 python 里做的那样，本篇为 <a href="https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/Basics" target="_blank" rel="noopener">mdn_JS对象基础</a>
，<a href="https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/Object_prototypes" target="_blank" rel="noopener">mdn_JS对象原型</a>
 的阅读笔记</p>

</blockquote>
<p>如果 <a href="https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/Object-oriented_programming" target="_blank" rel="noopener">面向对象编程基本概念</a>
 不太清楚的话，可以看一下这个链接，了解一下下面这些基本概念：derive 派生 | oriented 面向 | polymorphism 多态 | override 重写/重载 | encapsulation 封装 | private 私有 | delegation 委派 |</p>
<h2 id="从声明对象开始">从声明对象开始</h2>
<h3 id="手动声明对象字面量">手动声明对象（字面量）</h3>
<p>在 JS 中声明一个对象实际上和声明一个字典一样，使用 <code>{}</code> 就可以声明一个对象，{}中可以包含属性甚至函数，下面给出一个例子：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">person</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">name</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;aiken&#34;</span><span class="p">,</span> <span class="s2">&#34;metis&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">	<span class="nx">age</span><span class="o">:</span> <span class="mi">26</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="nx">bio</span><span class="o">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`</span><span class="si">${</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="si">}</span><span class="sb"> </span><span class="si">${</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="sb"> now is </span><span class="si">${</span><span class="k">this</span><span class="p">.</span><span class="nx">age</span><span class="si">}</span><span class="sb"> years old`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="nx">introduce</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`hello! i&#39;m </span><span class="si">${</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="si">}</span><span class="sb">.`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以看出该声明的对象中，不仅包含属性: name, age, 还包含方法 bio, introduce,可以看出方法存在两种不同的写法，更常用的是第二种简写。</p>
<p>这种手动写出对象的内容来创建的特定对象叫做对象字面量(object literal)，与从定义好的类实例化出来的对象不同。</p>
<h3 id="基于函数来批量声明对象">基于函数来批量声明对象</h3>
<p>当我们需要批量创建多个同类对象的时候，按照上面的方法来定义就会显得十分麻烦，这个时候我们可以使用函数来批量声明对象。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">createPerson</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">age</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="kr">const</span> <span class="nx">obj</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">	<span class="nx">obj</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="nx">name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="nx">obj</span><span class="p">.</span><span class="nx">age</span> <span class="o">=</span> <span class="nx">age</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="nx">obj</span><span class="p">.</span><span class="nx">bio</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">		<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`</span><span class="si">${</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="si">}</span><span class="sb"> now is </span><span class="si">${</span><span class="k">this</span><span class="p">.</span><span class="nx">age</span><span class="si">}</span><span class="sb"> years old`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">};</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="nx">obj</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">aiken</span> <span class="o">=</span> <span class="nx">createPerson</span><span class="p">(</span><span class="s1">&#39;aiken&#39;</span><span class="p">,</span><span class="s1">&#39;26&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">metisy</span> <span class="o">=</span> <span class="nx">createPerson</span><span class="p">(</span><span class="s1">&#39;metis&#39;</span><span class="p">,</span> <span class="s1">&#39;25&#39;</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>通过函数来声明对象的时候：用首先定义一个空对象，然后去修改对象属性和对象的方法，实现批量处理。</p>
<h3 id="this-使用和含义">&ldquo;this&rdquo; 使用和含义</h3>
<p>this 指代代码运行时调用 this 的对象本身，这在定义单个对象字面量的时候可能没什么用，但是当我们有多个对象，这样这种时候通过使用 this，就可以使得函数定义是更通用的，就像上面的例子中，<code>aiken.bio</code> 和 <code>metisy.bio</code> 都能正确的打印出其年纪和名称。</p>
<h3 id="使用类构造函数来声明对象">使用类(构造函数)来声明对象</h3>
<p>使用类来声明对象是各种编程语言中最通用的一种声明对象的方式，JS 一切皆为对象的设计思想，使得 JS 中定义类的方式和定义函数的方式实际上是十分相似的，这里主要的区分在于用构造函数声明新对象的时候，我们使用 <code>new</code> 关键字。下面给出一个例子：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">Person</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">age</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="c1">// 命名类的时候和其他语言一样，使用大写字母开头。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="k">this</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="nx">name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">this</span><span class="p">.</span><span class="nx">age</span> <span class="o">=</span> <span class="nx">age</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">this</span><span class="p">.</span><span class="nx">bio</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">		<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`</span><span class="si">${</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="si">}</span><span class="sb"> now is </span><span class="si">${</span><span class="k">this</span><span class="p">.</span><span class="nx">age</span><span class="si">}</span><span class="sb"> years old`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">aiken</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Person</span><span class="p">(</span><span class="s1">&#39;aiken&#39;</span><span class="p">,</span> <span class="mi">26</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">metis</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Person</span><span class="p">(</span><span class="s1">&#39;metis&#39;</span><span class="p">,</span> <span class="mi">25</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以看出，使用构造函数的方式的时候，我们无需指定返回值，但需要使用 new 关键词去声明新的对象。</p>
<h2 id="对象属性和方法的访问和修改">对象属性和方法的访问和修改</h2>



  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>调用对象的属性和方法主要有两种方式：点访问法和括号访问法；两种方式在大多数情况下是通用的，但是诸如希望遍历其中的属性，或者说要访问的属性是一个不确定的变量的时候，这种时候只能使用括号访问法。</p>

</blockquote>
<h3 id="访问对象成员">访问对象成员</h3>
<p>这里我们以上文的 <code>Person</code> 类构造出来的对象 <code>aiken</code> 为例，当我们需要访问其中的属性值或者方法的时候：</p>
<ul>
<li>点表示法：<code>console.log(aiken.name)</code> 这里的对象可以按照一个命名空间去理解，选择 aiken 命名空间中的 name 变量；</li>
<li>括号表示法：<code>console.log(aiken['name'])</code> 就像字典/数组一样去访问其中的属性；</li>
</ul>
<p>通常而言但就对象属性访问而言，点表示法是更通用优雅的一种，而括号表示法主要在我们希望访问一个不确定的属性的时候，使用变量存储要访问的字段的情况；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">classFactor</span><span class="p">(</span><span class="nx">attrName</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">aiken</span><span class="p">[</span><span class="nx">attrName</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nx">classFactor</span><span class="p">(</span><span class="s2">&#34;name&#34;</span><span class="p">);</span> <span class="c1">// 访问aiken的name
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">classFactor</span><span class="p">(</span><span class="s2">&#34;age&#34;</span><span class="p">);</span>  <span class="c1">// 访问aiken的age
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这种情况也经常用于交互场景，通过 UI 设置对应的属性名称和属性值；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">myDataName</span> <span class="o">=</span> <span class="nx">nameInput</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">myDataValue</span> <span class="o">=</span> <span class="nx">nameInput</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nx">aiken</span><span class="p">[</span><span class="nx">myDataName</span><span class="p">]</span> <span class="o">=</span> <span class="nx">myDataValue</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="对象成员设置">对象成员设置</h3>
<p>通过上述的访问对象成员的方法，我们可以获取到一个对象的任一成员（属性、方法），可以通过简单的赋值符号 = 去修改（更新）改成员。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">aiken</span><span class="p">.</span><span class="nx">age</span> <span class="o">=</span> <span class="s1">&#39;27&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nx">aiken</span><span class="p">[</span><span class="s1">&#39;age&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;28&#39;</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>也可以用同样的操作去创建新的成员（属性、方法）</p>
<h2 id="原型与继承">原型与继承</h2>



  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>原型实际上就是别的语言中所说的&quot;基类&quot;或者&quot;父类&quot;，js 的继承方法和其他语言中我们熟悉的方法有所不同，这里需要注意区分。</p>

</blockquote>
<p>JS 中的继承和其他语言一样，会继承父类中的属性和方法，当我们在调用的时候还是沿着继承的链条逐渐查询的（先子，后父），这里就不在赘言。</p>
<h3 id="一些基础特性">一些基础特性</h3>
<p>开始<a href="https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/Object_prototypes" target="_blank" rel="noopener">学习原型与继承</a>
之前，这里要介绍两个后面会比较常用到的小特性：</p>
<p>第一个特性是，使用 <code>Object.getPrototypeOf</code> 函数可以获取到对应对象的原型，这个时候结合一个 do&hellip;while 循环我们就可以打印出整条原型链。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">getPrototypeLink</span><span class="p">(</span><span class="nx">object</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">do</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">object</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">getPrototypeOf</span><span class="p">(</span><span class="nx">object</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">object</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span><span class="k">while</span><span class="p">(</span><span class="nx">object</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 当找不到原型的时候就会返回unll终止循环
</span></span></span><span class="line"><span class="cl"><span class="c1">// 通常而言最基础的原型是Object.prototype,所有的对象都会默认拥有它，再往前就是null
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>第二个特性是，定义完一个对象，例如 <code>Person</code>,这个时候在控制台键入</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">person</span><span class="p">.</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>控制台会将对象可用的一系列属性列出，该特性可以用来检查继承的发生与否，以及情况；同时可以发现，除了我们定义的各种属性之外，还有一些隐式继承至默认原型的属性：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">__defineGetter__</span>
</span></span><span class="line"><span class="cl"><span class="nx">__defineSetter__</span>
</span></span><span class="line"><span class="cl"><span class="nx">__lookupGetter__</span>
</span></span><span class="line"><span class="cl"><span class="nx">__lookupSetter__</span>
</span></span><span class="line"><span class="cl"><span class="nx">__proto__</span>
</span></span><span class="line"><span class="cl"><span class="nx">city</span>
</span></span><span class="line"><span class="cl"><span class="nx">constructor</span>
</span></span><span class="line"><span class="cl"><span class="nx">greet</span>
</span></span><span class="line"><span class="cl"><span class="nx">hasOwnProperty</span>
</span></span><span class="line"><span class="cl"><span class="nx">isPrototypeOf</span>
</span></span><span class="line"><span class="cl"><span class="nx">propertyIsEnumerable</span>
</span></span><span class="line"><span class="cl"><span class="nx">toLocaleString</span>
</span></span><span class="line"><span class="cl"><span class="nx">toString</span>
</span></span><span class="line"><span class="cl"><span class="nx">valueOf</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><blockquote>
<p>其中像是 <code>toString</code> 或者 <code>valueOf</code> 这些方法，可以适当的去了解下，后面用到的情况可能会比较多。</p>
</blockquote>
<p>可以发现 JS 中<strong>所有的对象</strong>都有一个内置属性 <code>__proto__</code> ，该属性指向我们对象的原型（父类），通常用 <code>Object.getPrototypeOf</code> 去获取对应的对象，同样<strong>如果修改/指定该属性的值，在 js 中，就是继承操作</strong>，这个后续进行讲解。</p>
<h3 id="属性遮蔽">属性遮蔽</h3>
<p>当对象和其原型同时定义了同名的属性，在访问该属性的时候，首先会在对象本身的命名空间中进行搜索，当搜索不到的时候才会去搜索父类，因此这个时候对象的这个属性就对原型中的对应属性出现了遮蔽；</p>
<h3 id="设置原型类似继承">设置原型（类似继承）</h3>
<p>JS 中设置原型有几种不同的方式，包括使用 <code>Object.create()</code> 和使用构造函数的方式；</p>
<h4 id="objectcreate">Object.Create</h4>
<p><code>Object.create(ptorotype-object)</code> 方法可以创建一个新的对象，并允许指定一个用作新对象原型的对象。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">personPrototype</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">greet</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">		<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;hello!&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">aiken</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">create</span><span class="p">(</span><span class="nx">personPrototype</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">aiken</span><span class="p">.</span><span class="nx">greet</span><span class="p">();</span> <span class="c1">// hello!
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="使用构造函数">使用构造函数</h4>
<p>JS 中，所有的函数都有一个 <code>prototype</code> 属性，当调用一个函数作为构造函数时（即使用 <code>new</code>）这个<strong>属性本身</strong>会被设置为新构造对象的原型（按照惯例会存在 <code>__proto__</code> 的属性中），因此，如果设置构造函数的 <code>prototype</code> 属性到某个原型上，就能确定构造出来的新的对象都会继承该原型。</p>
<p>具体的操作如下, 这里沿用上述的 <code>personPrototype</code> 来做说明。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">Person</span><span class="p">(</span><span class="nx">name</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">	<span class="k">this</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="nx">name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">Object</span><span class="p">.</span><span class="nx">assign</span><span class="p">(</span><span class="nx">Person</span><span class="p">.</span><span class="nx">prototype</span><span class="p">,</span> <span class="nx">personPrototype</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">aiken</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Person</span><span class="p">(</span><span class="s1">&#39;aiken&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">aiken</span><span class="p">.</span><span class="nx">greet</span><span class="p">();</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这也解释了为什么我们查找原型的时候，总会在原型的名称后面加上 <code>.prototype</code>，在上述的对象 <code>aiken</code> 中，自身特有的属性叫做<strong>自有属性</strong>，可以使用 <code>Object.hasOwn(obj, attr)</code> 检查 attr 是不是 obj 的自有属性。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nb">Object</span><span class="p">.</span><span class="nx">hasOwn</span><span class="p">(</span><span class="nx">aiken</span><span class="p">,</span> <span class="s2">&#34;name&#34;</span><span class="p">);</span> <span class="c1">// true
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nb">Object</span><span class="p">.</span><span class="nx">hasOwn</span><span class="p">(</span><span class="nx">aiken</span><span class="p">,</span> <span class="s2">&#34;greet&#34;</span><span class="p">);</span> <span class="c1">// false;
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="js-面向对象编程的特点">JS 面向对象编程的特点</h2>
<p><a href="https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/Object-oriented_programming" target="_blank" rel="noopener">面向对象编程基本概念</a>
 这一文中除了对整个面向对象编程的基本概念有讲解，也说明了 JS 的面向对象编程的特点，建议阅读，简单一点：</p>
<ol>
<li>其他大多语言都是基于类的面向对象编程，对象必须有类创建出来，两者是不同的概念，定义类和实例化对象的方法是不同的，而 js 从创建对象字面量的方式就可以知道，JS 无需类就可以创建对象（类本身也会是一个对象）.</li>
<li>基于(类本身也是一个对象)这个假定，就可以发现，原型链和继承有一样的层级结构，但是本质上是不一样的，原型链实际上是一个链表，一个对象的原型实际上是另一个对象，之间通过 <code>_proto_</code> 属性进行连接，这是一种委派。</li>
</ol>
<p>但是整体在使用上，原型和 js 的构造函数可以基本上实现面向对象的编程特性，但是可能还不太够用，因此 JS 还提供了一些别的特性：参见下一节。</p>
<h2 id="javascript-中的类">JavaScript 中的类</h2>



  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>这里介绍的类实际上底层使用的仍然是原型，这是通过引入 class 的关键字来使创建原型链更加的便捷以及和其他语言对齐。</p>

</blockquote>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">class</span> <span class="nx">Person</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="nx">constructor</span><span class="p">(</span><span class="nx">name</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">		<span class="k">this</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="nx">name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="nx">introduceSelf</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">		<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`hi! I&#39;m </span><span class="si">${</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">aikenhong</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Person</span><span class="p">(</span><span class="s2">&#34;aikenhong&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">aikenhong</span><span class="p">.</span><span class="nx">introduceSelf</span><span class="p">();</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>上面这个 JS 中的类的声明中有以下的几点：</p>
<ul>
<li>声明有 name 属性（可选，构造函数中使用 this 那行会在初始化 name 属性前自动创建它，但是列出来可以方便阅读）</li>
<li>一个需要 <code>name</code> 参数的构造函数</li>
<li>一个成员方法</li>
</ul>
<p>也可以初始化默认值，就像 <code>name = &quot;&quot;; </code>,构造函数使用 <code>constructor</code> 关键字来声明，这里的 new 创建新的对象的时候，就会创建新的对象，将 <code>this</code> 绑定到新的对象,执行 <code>constructor</code> 函数，返回新的对象。</p>
<h3 id="省略构造函数">省略构造函数</h3>
<p>如果不需要初始化什么变量，只需要提供基准方法，那就可以省略构造函数，这个会自动生成。</p>
<h3 id="继承">继承</h3>
<p>使用 <code>extends</code> 指定基类，实现继承，并用 <code>super</code> 调用父类的构造函数，然后覆盖父类的方法，并新增一个新的方法，例子如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">class</span> <span class="nx">Professor</span> <span class="kr">extends</span> <span class="nx">Person</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">teaches</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="nx">constructor</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span> <span class="nx">teaches</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">		<span class="kr">super</span><span class="p">(</span><span class="nx">name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="k">this</span><span class="p">.</span><span class="nx">teaches</span> <span class="o">=</span> <span class="nx">teaches</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="nx">introduceSelf</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">		<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">			<span class="sb">`My name is </span><span class="si">${</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span><span class="si">}</span><span class="sb">, and i will be your </span><span class="si">${</span><span class="k">this</span><span class="p">.</span><span class="nx">teaches</span><span class="si">}</span><span class="sb"> profesor.`</span>
</span></span><span class="line"><span class="cl">		<span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="nx">grade</span><span class="p">(</span><span class="nx">paper</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">		<span class="kr">const</span> <span class="nx">grades</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">random</span><span class="p">()</span> <span class="o">*</span> <span class="p">(</span><span class="mi">5</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">grades</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">aiken</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Professor</span><span class="p">(</span><span class="s2">&#34;Aiken&#34;</span><span class="p">,</span> <span class="s2">&#34;CS&#34;</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="封装私有变量和私有方法">封装（私有变量和私有方法）</h3>
<p>这一节主要就介绍一下怎么将对象和方法变成私有的，在命名之前添加 <code>#</code></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">class</span> <span class="nx">Person</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="err">#</span><span class="nx">name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="nx">constructor</span><span class="p">(</span><span class="nx">name</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">		<span class="k">this</span><span class="p">.</span><span class="nx">name</span> <span class="o">=</span> <span class="nx">name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="nx">introduceSelf</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">		<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`my name is </span><span class="si">${</span><span class="nx">name</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="err">#</span><span class="nx">privateLogHead</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">		<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;log head&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="nx">publicLogHead</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">		<span class="nx">privateLogHead</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">examplePerson</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Person</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">examplePerson</span><span class="p">.</span><span class="err">#</span><span class="nx">name</span><span class="p">;</span> <span class="c1">// syntax error
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">examplePerson</span><span class="p">.</span><span class="nx">introduceSelf</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">examplePerson</span><span class="p">.</span><span class="err">#</span><span class="nx">privateLogHead</span><span class="p">();</span> <span class="c1">// syntax error
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">examplePerson</span><span class="p">.</span><span class="nx">publicLogHead</span><span class="p">();</span> 
</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="练习">练习</h2>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/Object_building_practice" target="_blank" rel="noopener">碰撞弹球</a>
 ：可以帮助熟悉原型等相关概念，建议尝试或者阅读。</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features" target="_blank" rel="noopener">碰撞弹球2</a>
： 添加恶魔圈来消除原本的弹球，实战。</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>LearnWeb18-JS03-事件</title>
      <link>https://aikenh.cn/posts/learnweb18-js03-%E4%BA%8B%E4%BB%B6/</link>
      <pubDate>Wed, 17 Apr 2024 09:31:23 +0000</pubDate>
      <guid>https://aikenh.cn/posts/learnweb18-js03-%E4%BA%8B%E4%BB%B6/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-summary&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Summary&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;web-js 中主要的编程方式就是需要结合browser 的事件和属性来实现对页面的动态控制，事件章节可以说是web 动态编程中的核心部分了，了解主要存在和需要被控制的事件是相当重要的。&lt;/p&gt;

&lt;/blockquote&gt;
&lt;h2 id=&#34;常见的浏览器事件&#34;&gt;常见的浏览器事件&lt;/h2&gt;
&lt;p&gt;下面列出一些常见的事件类型和具体事件，更多的事件可以&lt;a href=&#34;https://developer.mozilla.org/zh-CN/docs/Web/Events&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;参考Mdn&lt;/a&gt;
，在设计页面的时候可以考虑我们希望获得什么效果来找寻是否有对应的事件来构建对应的动态响应。&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>web-js 中主要的编程方式就是需要结合browser 的事件和属性来实现对页面的动态控制，事件章节可以说是web 动态编程中的核心部分了，了解主要存在和需要被控制的事件是相当重要的。</p>

</blockquote>
<h2 id="常见的浏览器事件">常见的浏览器事件</h2>
<p>下面列出一些常见的事件类型和具体事件，更多的事件可以<a href="https://developer.mozilla.org/zh-CN/docs/Web/Events" target="_blank" rel="noopener">参考Mdn</a>
，在设计页面的时候可以考虑我们希望获得什么效果来找寻是否有对应的事件来构建对应的动态响应。</p>
<table>
  <thead>
      <tr>
          <th>事件类型</th>
          <th>具体事件</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>鼠标事件</strong></td>
          <td>点击、选择、悬停、拖拽、滚轮、焦点(focus, blur)</td>
      </tr>
      <tr>
          <td><strong>键盘事件</strong></td>
          <td>按键、剪切板、文本输入</td>
      </tr>
      <tr>
          <td><strong>窗口事件</strong></td>
          <td>调整大小、窗口关闭</td>
      </tr>
      <tr>
          <td><strong>页面事件</strong></td>
          <td>加载结束、错误发生、CSS 变换、DOM 事件</td>
      </tr>
      <tr>
          <td><strong>自定义事件</strong></td>
          <td>点击按钮，表单提交</td>
      </tr>
      <tr>
          <td><strong>多媒体事件</strong></td>
          <td>视频播放、暂停、结束</td>
      </tr>
  </tbody>
</table>
<p>在确定了事件之后，就需要对事件附加一个<strong>事件处理器（监听器）</strong>，当事件触发的时候，运行指定的js 代码对该事件做出相应。</p>
<h2 id="事件处理器">事件处理器</h2>



  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>通常而言，我们使用特定的 <code>element</code> 调用 <code>addEventListener(event, function)</code> 添加一个事件监听器，当参数中指定的事件 <code>event</code> 在对应元素上发生，就调用对应的 <code>function</code> 执行相应的变动，如果不是通用的函数，这里经常可以看到使用匿名函数去定义对应的操作。</p>

</blockquote>
<h3 id="添加事件处理器">添加事件处理器</h3>
<p>因此对于一个事件而言，实际上包含的操作有以下的几个：找到 DOM 中要操作的对应元素、添加事件监听器、选择对应的事件、定义对应的操作函数；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">btn</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;button&#34;</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">random</span><span class="p">(</span><span class="nx">number</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">random</span><span class="p">()</span> <span class="o">*</span> <span class="p">(</span><span class="nx">number</span> <span class="o">+</span> <span class="mi">1</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">changeBackground</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">rndCol</span> <span class="o">=</span> <span class="sb">`rgb(</span><span class="si">${</span><span class="nx">random</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span><span class="si">}</span><span class="sb">, </span><span class="si">${</span><span class="nx">random</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span><span class="si">}</span><span class="sb">, </span><span class="si">${</span><span class="nx">random</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span><span class="si">}</span><span class="sb">)`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">backgroundColor</span> <span class="o">=</span> <span class="nx">rndCol</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">btn</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;click&#34;</span><span class="p">,</span> <span class="nx">changeBackground</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以为同一个事件设置多个处理器，也就是添加多个 function，对于添加事件来说其中 <code>addEventListener</code> 是最为通用的，可以绑定多种事件，不过除了 <code>addEventListener</code> 之外，还有一些特殊事件的添加监听的方法，例如 click 事件有一个内联的监听器：<code>onclick</code>。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">btn</span><span class="p">.</span><span class="nx">onlick</span> <span class="o">=</span> <span class="nx">changeBackground</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>虽然有一些示例在 html 中绑定事件内联，但是最好还是分开在 js 中绑定更好。</p>
<h3 id="移除监听器">移除监听器</h3>
<p>如果使用 <code>addEventListener</code> 添加了一个事件处理器，可以使用 <code>removeEventListener(event, function)</code> 方法将该监听器删除，同样要使用对应的 <code>element</code> ，<code>event</code>，<code>function</code>。</p>
<p>也可以对元素调用 <code>abort</code> 移除与该元素相关的所有事件处理器：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">element</span><span class="p">.</span><span class="nx">abort</span><span class="p">();</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="事件对象">事件对象</h3>
<p>有时候在事件处理函数内部，有时候会看到一些固定名称的参数，例如 <code>event</code>，<code>evt</code>，<code>e</code> 这些是事件对象，它会自动传递给事件处理函数。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">btn</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;button&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">random</span><span class="p">(</span><span class="nx">number</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">random</span><span class="p">()</span> <span class="o">*</span> <span class="p">(</span><span class="nx">number</span> <span class="o">+</span> <span class="mi">1</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">bgChange</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">rndCol</span> <span class="o">=</span> <span class="sb">`rgb(</span><span class="si">${</span><span class="nx">random</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span><span class="si">}</span><span class="sb">, </span><span class="si">${</span><span class="nx">random</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span><span class="si">}</span><span class="sb">, </span><span class="si">${</span><span class="nx">random</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span><span class="si">}</span><span class="sb">)`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">backgroundColor</span> <span class="o">=</span> <span class="nx">rndCol</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">btn</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;click&#34;</span><span class="p">,</span> <span class="nx">bgChange</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>例如上文中的 <code>e</code> 指的是事件对象，<code>e.target</code> 指的是这个按钮本身，类似的大多数事件对象都会有一些额外的属性和方法可供使用，这个可以参考 <a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Event" target="_blank" rel="noopener">event-object</a>
，找到对应 event 的事件对象的属性。</p>
<h3 id="阻止默认行为">阻止默认行为</h3>
<p>最常见的是 web 表单，当用户输入的内容不符合 format 的时候，我们希望直接阻止默认提交行为，不将其提交到服务器去处理。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">form</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;submit&#34;</span><span class="p">,</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">fname</span><span class="p">.</span><span class="nx">value</span> <span class="o">===</span> <span class="s2">&#34;&#34;</span> <span class="o">||</span> <span class="nx">lname</span><span class="p">.</span><span class="nx">value</span> <span class="o">===</span> <span class="s2">&#34;&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">para</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="s2">&#34;You need to fill in both names!&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="事件行为传播逻辑">事件行为/传播逻辑</h2>
<h3 id="事件冒泡">事件冒泡</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">button</span><span class="p">&gt;</span>点我！<span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>以上述 DOM 为例，当我们点击 btn 的时候，btn、div、body 会依次冒泡触发 click 事件；</p>
<p>这种冒泡有时候会因为函数之间的冲突导致一些不希望出现的问题，这种时候我们可以对事件传递一个<strong>阻止冒泡</strong>的元素方法 <code>stopPropagation</code>，防止其继续向父级冒泡。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">video</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;click&#34;</span><span class="p">,</span> <span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">event</span><span class="p">.</span><span class="nx">stopPropagation</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="nx">video</span><span class="p">.</span><span class="nx">play</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="事件捕获">事件捕获</h3>
<p>事件传播的另一种形式是事件捕获，这个就像事件冒泡，但是顺序是相反的，也就是从最外层逐渐到最里层的形式，但是需要在 <code>addEventListener()</code> 的 <code>capture</code> 选项中启用它，这样的顺序就会是完全相反的。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">output</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;#output&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">handleClick</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">output</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">+=</span> <span class="sb">`你在 </span><span class="si">${</span><span class="nx">e</span><span class="p">.</span><span class="nx">currentTarget</span><span class="p">.</span><span class="nx">tagName</span><span class="si">}</span><span class="sb"> 元素上进行了点击\n`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">container</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;#container&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">button</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;button&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;click&#34;</span><span class="p">,</span> <span class="nx">handleClick</span><span class="p">,</span> <span class="p">{</span> <span class="nx">capture</span><span class="o">:</span> <span class="kc">true</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="nx">container</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;click&#34;</span><span class="p">,</span> <span class="nx">handleClick</span><span class="p">,</span> <span class="p">{</span> <span class="nx">capture</span><span class="o">:</span> <span class="kc">true</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="nx">button</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;click&#34;</span><span class="p">,</span> <span class="nx">handleClick</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>例如上面的这串代码，有capture 和没有的顺序是完全相反的。</p>
<h3 id="事件委托">事件委托</h3>
<p>上述的事件冒泡和事件捕获的一个应用，例如，我们将页面划分成n 个区域，希望每个区域都支持在点击后随机设置其背景颜色，</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;tile&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;tile&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;tile&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;tile&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>但我们显然不希望对每个子元素都进行一次绑定，尤其是子元素的数量多起来以后，因此，更简单的是我们对父元素设置事件处理器，然后基于事件冒泡来确认用户点击每个区域时函数被执行。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">random</span><span class="p">(</span><span class="nx">number</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">random</span><span class="p">()</span> <span class="o">*</span> <span class="nx">number</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">bgChange</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">rndCol</span> <span class="o">=</span> <span class="sb">`rgb(</span><span class="si">${</span><span class="nx">random</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span><span class="si">}</span><span class="sb">, </span><span class="si">${</span><span class="nx">random</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span><span class="si">}</span><span class="sb">, </span><span class="si">${</span><span class="nx">random</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span><span class="si">}</span><span class="sb">)`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">rndCol</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">container</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;#container&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">container</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;click&#34;</span><span class="p">,</span> <span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">event</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">backgroundColor</span> <span class="o">=</span> <span class="nx">bgChange</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><blockquote>
<p><strong>备注：</strong> 在这个例子中，我们使用 <code>event.target</code> 来获取事件的目标元素（也就是最里面的元素）。如果我们想访问处理这个事件的元素（在这个例子中是容器），我们可以使用 <code>event.currentTarget</code>。</p>
</blockquote>
<p>可以去这里 <a href="https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Building_blocks/Events#%E4%BA%8B%E4%BB%B6%E5%AF%B9%E8%B1%A1" target="_blank" rel="noopener">link</a>
 查看对应效果，理解以下这个事件是怎么发生的，其实最关键的是 <a href="https://juejin.cn/post/6844903506399199246" target="_blank" rel="noopener">target 和currentTarget 的区分</a>
，简单的讲：</p>
<ul>
<li>target 是实际触发事件的元素</li>
<li>currentTarget 始终是绑定监听器的元素。</li>
</ul>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240425005404.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240425005404.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240425005404.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
]]></content:encoded>
    </item>
    <item>
      <title>LearnWeb17-JS02-Intro</title>
      <link>https://aikenh.cn/posts/learnweb17-js02-intro/</link>
      <pubDate>Fri, 29 Mar 2024 23:59:08 +0000</pubDate>
      <guid>https://aikenh.cn/posts/learnweb17-js02-intro/</guid>
      <description>&lt;h2 id=&#34;js-基础语法&#34;&gt;JS 基础语法&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;该部分的学习除了 MDN 的相关知识，会结合数据结构的内容来进行学。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;语言的第一印象和 python 有许多相似的地方。语法上可能大差不差，在循环和其他一些变量上又有一些和 C#,CPP 相似的地方。&lt;/p&gt;
&lt;h3 id=&#34;basic-rules-基础规则简介&#34;&gt;Basic Rules 基础规则简介&lt;/h3&gt;
&lt;p&gt;首先介绍基本的编写规则:如注释、缩进规则、变量规则等&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;注释&lt;/strong&gt;：CPP 相同使用 &lt;code&gt;//&lt;/code&gt; 和 &lt;code&gt;/*  */&lt;/code&gt; 进行行/块注释。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;句尾&lt;/strong&gt; &lt;code&gt;;&lt;/code&gt; ：单行单条语句结束可以无需 &lt;code&gt;;&lt;/code&gt; (但为了规范和明确可以加上)，同行多个语句可以用 &lt;code&gt;;&lt;/code&gt; 进行语句的区分。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;变量&#34;&gt;变量&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;声明变量使用：&lt;a href=&#34;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/var&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;code&gt;var&lt;/code&gt;&lt;/a&gt;
, &lt;a href=&#34;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/let&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;code&gt;let&lt;/code&gt;&lt;/a&gt;
, &lt;a href=&#34;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/const&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;code&gt;const&lt;/code&gt;&lt;/a&gt;
 三个关键词；其中 &lt;code&gt;let&lt;/code&gt; 和 &lt;code&gt;const&lt;/code&gt; 是相似的，用于声明块级作用域的局部变量，只有在声明的位置之后才能使用，唯一的区别在于 &lt;code&gt;const&lt;/code&gt; 声明的常量不能用赋值运算符直接更改，（但如果是个对象，它的属性可以被添加、更新、删除）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;变量定义：&lt;/strong&gt;(另起一个 Paragraph 表示尊重) JS 为非强类型语言(即类似 python 而非 cpp)，为&lt;strong&gt;动态类型语言&lt;/strong&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;let&lt;/code&gt; 或 &lt;code&gt;var&lt;/code&gt; 关键字定义变量。&lt;/li&gt;
&lt;li&gt;（最推荐）最推荐使用 &lt;code&gt;let&lt;/code&gt; 进行变量的声明，var 对变量定义位置的要求更低，使用 var 编写可能会方便，但是在后续维护和阅读中可能会体验很差。使用 &lt;code&gt;let&lt;/code&gt; 然后和别的语言一样声明和使用变量。&lt;/li&gt;
&lt;li&gt;可以使用 &lt;code&gt;typeof&lt;/code&gt; 来检查变量类型&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中对于变量的定义上，Var 和 let 的详细差别可以参考 &lt;a href=&#34;https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/First_steps/Variables#var_%E4%B8%8E_let_%E7%9A%84%E5%8C%BA%E5%88%AB&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;var与let的区别&lt;/a&gt;
，&lt;a href=&#34;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/var#%E5%8F%98%E9%87%8F%E6%8F%90%E5%8D%87&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;var变量提升&lt;/a&gt;
，简单的讲 var 的定义会先于所有的语句执行，声明一个全局的变量。下面简单介绍一下各种不同的数据类型：&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h2 id="js-基础语法">JS 基础语法</h2>
<blockquote>
<p>该部分的学习除了 MDN 的相关知识，会结合数据结构的内容来进行学。</p>
</blockquote>
<p>语言的第一印象和 python 有许多相似的地方。语法上可能大差不差，在循环和其他一些变量上又有一些和 C#,CPP 相似的地方。</p>
<h3 id="basic-rules-基础规则简介">Basic Rules 基础规则简介</h3>
<p>首先介绍基本的编写规则:如注释、缩进规则、变量规则等&hellip;</p>
<ul>
<li><strong>注释</strong>：CPP 相同使用 <code>//</code> 和 <code>/*  */</code> 进行行/块注释。</li>
<li><strong>句尾</strong> <code>;</code> ：单行单条语句结束可以无需 <code>;</code> (但为了规范和明确可以加上)，同行多个语句可以用 <code>;</code> 进行语句的区分。</li>
</ul>
<h3 id="变量">变量</h3>
<blockquote>
<p>声明变量使用：<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/var" target="_blank" rel="noopener"><code>var</code></a>
, <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/let" target="_blank" rel="noopener"><code>let</code></a>
, <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/const" target="_blank" rel="noopener"><code>const</code></a>
 三个关键词；其中 <code>let</code> 和 <code>const</code> 是相似的，用于声明块级作用域的局部变量，只有在声明的位置之后才能使用，唯一的区别在于 <code>const</code> 声明的常量不能用赋值运算符直接更改，（但如果是个对象，它的属性可以被添加、更新、删除）</p>
</blockquote>
<p><strong>变量定义：</strong>(另起一个 Paragraph 表示尊重) JS 为非强类型语言(即类似 python 而非 cpp)，为<strong>动态类型语言</strong>，变量声明<strong>无需指定类型</strong>。但有以下几个注意的事项：</p>
<ul>
<li>（不推荐）不带关键字的变量声明会默认为全局变量。</li>
<li>（推荐）可以使用 <code>let</code> 或 <code>var</code> 关键字定义变量。</li>
<li>（最推荐）最推荐使用 <code>let</code> 进行变量的声明，var 对变量定义位置的要求更低，使用 var 编写可能会方便，但是在后续维护和阅读中可能会体验很差。使用 <code>let</code> 然后和别的语言一样声明和使用变量。</li>
<li>可以使用 <code>typeof</code> 来检查变量类型</li>
</ul>
<p>其中对于变量的定义上，Var 和 let 的详细差别可以参考 <a href="https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/First_steps/Variables#var_%E4%B8%8E_let_%E7%9A%84%E5%8C%BA%E5%88%AB" target="_blank" rel="noopener">var与let的区别</a>
，<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/var#%E5%8F%98%E9%87%8F%E6%8F%90%E5%8D%87" target="_blank" rel="noopener">var变量提升</a>
，简单的讲 var 的定义会先于所有的语句执行，声明一个全局的变量。下面简单介绍一下各种不同的数据类型：</p>
<p><strong>对象</strong>：JavaScript 里一切皆对象，一切皆可储存在变量里。这一点要牢记于心，字典也是一种对象，定义方式和 Python 一致：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">dog</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Spot&#34;</span><span class="p">,</span> <span class="nx">breed</span><span class="o">:</span> <span class="s2">&#34;Dalmatian&#34;</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="nx">dog</span><span class="p">.</span><span class="nx">name</span> <span class="c1">// 访问name属性。
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>数值：</strong> JS 只有一种数值类型 Number，不需要像 cpp 执行 int 和 float 之类的转换，说到数值类型，就需要对基本的运算符进行说明，这里简单列一下支持的一些运算符类型</p>
<table>
  <thead>
      <tr>
          <th style="text-align: center">Idx</th>
          <th>Col1</th>
          <th>Col2</th>
          <th>Col3</th>
          <th>Col4</th>
          <th>Col5</th>
          <th>Colo6</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: center">基础</td>
          <td>+</td>
          <td>-</td>
          <td>*</td>
          <td>/</td>
          <td>%</td>
          <td>**</td>
      </tr>
      <tr>
          <td style="text-align: center">自增自减</td>
          <td>*=</td>
          <td>(var)++</td>
          <td>(var)&ndash;</td>
          <td>+=</td>
          <td>-=</td>
          <td>/=</td>
      </tr>
      <tr>
          <td style="text-align: center">比较</td>
          <td>!==</td>
          <td>===</td>
          <td>&lt;</td>
          <td>&gt;</td>
          <td>&lt;=</td>
          <td>&gt;=</td>
      </tr>
  </tbody>
</table>
<p><strong>基本运算符</strong>：和大多数语言的基本运算符保持一致，这里需要特殊说明的只有<strong>相等的判断符</strong>，区别于其他语言，JS 中使用三个等号来判断相等；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">if</span> <span class="n">a</span> <span class="o">==</span> <span class="n">b</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">	<span class="nb">print</span><span class="p">(</span><span class="s2">&#34;a is equal to b&#34;</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>javascript</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="nx">a</span> <span class="o">===</span> <span class="nx">b</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;a is equal to b&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><blockquote>
<p>这里的函数定义和条件判断都更接近 cpp，使用{}将代码块来区分，而非单纯使用缩进。</p>
</blockquote>
<p><strong>字符串</strong>：JS 中字符串的定义方式支持使用 <code>&quot;&quot;</code>、<code>''</code> ，这和其他语言的支持是类似的，如果字符串中需要使用引号，也可以使用 <code>\</code> 进行转义，同时字符串支持 <code>+</code> 进行拼接。</p>
<p>此外，JS 还支持使用 ``<strong>反引号</strong>来包裹字符串，使用反引号的时候就可以很容易的在字符串中包含引号；而这不是反引号字符串最重要的特性，该反引号字符串的使用更类似于 shell 语言：</p>
<ul>
<li>使用反引号的字符串时，可以利用 <code>${}</code> 符号来包装变量和表达式。</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">output</span> <span class="o">=</span> <span class="sb">`我喜欢歌曲《</span><span class="si">${</span><span class="nx">song</span><span class="si">}</span><span class="sb">》。我给它打了 </span><span class="si">${</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nx">score</span> <span class="o">/</span> <span class="nx">highestScore</span><span class="p">)</span> <span class="o">*</span> <span class="mi">100</span>
</span></span><span class="line"><span class="cl"><span class="si">}</span><span class="sb"> 分。`</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>上面这是一个很典型的嵌入了表达式的情况，这种方式能够很方便的进行变量之间的交互，也具备比较好的可读性（如果变量命名的比较科学的话），此外反引号还具备以下的特性：</p>
<ul>
<li>多行表达可以直接换行，无需如 <code>&quot;&quot;</code> 等方式定义的字符串，需要嵌入 <code>\n</code> 转义的换行符</li>
<li>使用 <code> ${sub}:$ {value}:${pos}</code> 进行字符串拼接的可读性通常&gt;= 使用 <code>+</code> 进行字符串拼接</li>
</ul>
<p>介绍完了字符串的定义，介绍一下字符串的相关操作：</p>
<ul>
<li>首先，字符串可以使用 <code>string[idx]</code> 去获取字符串中 idx 的字符；</li>
<li>其次，字符串本身实际上也是一个<strong>对象类型</strong>，我们可以使用 <code>obj.method</code> 调用对应的字符串方法，这点和其他语言是一致的，无需多言，下面列出一些常用的字符串函数。</li>
</ul>
<table>
  <thead>
      <tr>
          <th style="text-align: center">IDX</th>
          <th>Col 1</th>
          <th>Col 2</th>
          <th>Col3</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: center">1</td>
          <td><code>.length</code></td>
          <td><code>.indexOf()</code> 找到对应字符(串)的下标</td>
          <td><code>.slice(start, end)</code></td>
      </tr>
      <tr>
          <td style="text-align: center">2</td>
          <td><code>.toLowerCase()</code></td>
          <td><code>.toUpperCase()</code></td>
          <td><code>.replace(old, new)</code></td>
      </tr>
      <tr>
          <td style="text-align: center"></td>
          <td></td>
          <td></td>
          <td></td>
      </tr>
      <tr>
          <td style="text-align: center">可以看出，字符串实际上和数组类型避不开亲属关系，下面就介绍一下数组</td>
          <td></td>
          <td></td>
          <td></td>
      </tr>
  </tbody>
</table>
<p><strong>数组</strong>：Python 一样可以存储多种类型在一个 Array 中，同样使用 <code>array[idx]</code> 访问对应 idx 的元素，使用 <code>.length</code> 获取数组的长度，通常用于循环中。</p>
<ul>
<li>支持 <code>push</code> , <code>pop</code> 在数组末尾增加或删除元素，pop 会返回刚删除的元素；</li>
<li>支持 <code>unshift</code>，<code>shift</code> 在数组前面添加和删除元素；</li>
</ul>
<p><strong>数组和字符串转换</strong>: 使用 split 从 string 到 array，使用 joint(&lsquo;符号&rsquo;) 从 array 到指定符号链接的字符串，或者使用 toString()使用默认符号链接成字符串</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">myStringData</span> <span class="o">=</span> <span class="s2">&#34;Manchester,London,Liverpool,Birmingham,Leeds,Carlisle&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">myArrayString</span> <span class="o">=</span> <span class="nx">myStringDate</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s2">&#34;,&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">StringAgain</span> <span class="o">=</span> <span class="nx">myArrayString</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s2">&#34;-&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">StringAgain</span> <span class="o">=</span> <span class="nx">myArrayString</span><span class="p">.</span><span class="nx">toString</span><span class="p">();</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="function-函数">Function 函数</h3>
<p>JS 的函数关键字和 Shell 的一样只需要使用 function 即可，实际上和 CPP 也是一样的只是无需指定类型。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>javascript</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">multipy</span><span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="kd">let</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">a</span> <span class="o">+</span> <span class="nx">b</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="nx">reuslt</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">res</span> <span class="o">=</span> <span class="nx">multipy</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">res</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>有趣的地方在于 <code>JS</code> 的类也是用 function 定义的，这可能是由于<strong>一切皆为对象</strong>这个特性，所谓函数可能实际上是一个只有单个调用结构的类。并没有作区分。</p>
<p><strong>定义默认参数</strong>：默认参数和可选参数是息息相关的，当我们定义了默认的参数，这个参数就可以选择性的不赋值，通过默认参数去赋值。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">hello</span><span class="p">(</span><span class="nx">name</span><span class="o">=</span><span class="s2">&#34;aiken&#34;</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`hello </span><span class="si">${</span><span class="nx">name</span><span class="si">}</span><span class="sb">!`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">hello</span><span class="p">(</span><span class="s1">&#39;aikenhong&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">hello</span><span class="p">();</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="匿名函数和箭头函数">匿名函数和箭头函数</h4>
<p>当有些函数我们并不打算复用，或者当一些函数希望接受另一个函数作为参数时，我们经常会看到匿名函数的使用，匿名函数经常用于这种函数作为参数的场景，这种场景下也经常使用箭头函数的写法来定义这个匿名函数。</p>
<p>匿名函数的基本定义方法如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">textBox</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;keydown&#34;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`You pressed &#34;</span><span class="si">${</span><span class="nx">event</span><span class="p">.</span><span class="nx">key</span><span class="si">}</span><span class="sb">&#34;.`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>通常使用箭头函数的写法去实现这样的匿名函数</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">textBox</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;keydown&#34;</span><span class="p">,</span> <span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`You pressed &#34;</span><span class="si">${</span><span class="nx">event</span><span class="p">.</span><span class="nx">key</span><span class="si">}</span><span class="sb">&#34;.`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果只给匿名函数传入一个参数的时候，该参数两侧的圆括号可以省略</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">textBox</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;keydown&#34;</span><span class="p">,</span> <span class="nx">event</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`You pressed &#34;</span><span class="si">${</span><span class="nx">event</span><span class="p">.</span><span class="nx">key</span><span class="si">}</span><span class="sb">&#34;.`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>甚至如果只有一个 return 的时候还能省略外层的大括号</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">textBox</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;keydown&#34;</span><span class="p">,</span> <span class="nx">event</span> <span class="p">=&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`You pressed &#34;</span><span class="si">${</span><span class="nx">event</span><span class="p">.</span><span class="nx">key</span><span class="si">}</span><span class="sb">&#34;.`</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>函数本身的作用域仅存在于内部，函数外面的都是全局作用域，</p>
<h3 id="event-事件">Event 事件</h3>
<blockquote>
<p>接下来我把用于 web 开发的 javascript 用 web-js 代称用来区分服务端的 js，服务端的 js 我直接用 nodejs 代称好了。</p>
</blockquote>
<p>在 web-js 中，与事件的交互应该是最为关键的一个环节了，通过浏览器和用户触发的各种事件（如点击，页面滚动，页面跳转）来触发 js 中编写的一个个行为，正是所谓赋予网页动态交互特性。</p>
<blockquote>
<p>可以复习 <a href="tmp/LearnWeb00-Web%e5%85%a5%e9%97%a8.md">LearnWeb00-Web入门</a>
 中 How JavaScript Works 中讲到的原生异步处理机制，此处有使用 windows 监听的。</p>
</blockquote>
<p>下面引一个 MDN 中的例子做一些简单的说明：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>javascript</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;html&#34;</span><span class="p">).</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;click&#34;</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">alert</span><span class="p">(</span><span class="s2">&#34;别戳我，我怕疼。&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>👍 这里有个有趣的<strong>匿名函数写法</strong>，使用 <code>() =&gt; {}</code> 定义一个匿名函数，实际上也可以用下面这个完整的表达方式：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s1">&#39;html&#39;</span><span class="p">).</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;click&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">alert</span><span class="p">(</span><span class="s2">&#34;别戳我&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>此处的例子可解释为：使用 document（DOM）接口中的 <code>querySelector</code> 选择 html 元素添加对于 <code>click</code> 时间的监听，并在监听到点击行为的时候弹出别戳我的弹窗。</p>
<p>Selector 可以参考 HTML 部分选择器的含义去理解，具体可选择可能还是要参考 DOM API 中的说明，但是理论上应该会和 HTML 中的定义方式保持一致。</p>
<p><strong>例子 2</strong> 监听图片点击事件，切换背景图片，这里有两种写法和重要的 API 函数 <code>getAttribute</code> 和 <code>setAttribute</code>。</p>
<p>写法一：使用图片变量的 <code>OnClick</code> 事件（这里说明了变量本身是会携带一些事件定义，并非只有 AddListner 一种监听）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>javascript</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">ele_img</span><span class="p">.</span><span class="nx">onclick</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">src</span> <span class="o">=</span> <span class="nx">ele_img</span><span class="p">.</span><span class="nx">getAttribute</span><span class="p">(</span><span class="s2">&#34;src&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">src</span> <span class="o">===</span> <span class="s2">&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/80a5366f89dfbd27ec46f669e0eac84.jpg&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">ele_img</span><span class="p">.</span><span class="nx">setAttribute</span><span class="p">(</span><span class="s2">&#34;src&#34;</span><span class="p">,</span> <span class="s2">&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231005005911.png&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">ele_img</span><span class="p">.</span><span class="nx">setAttribute</span><span class="p">(</span><span class="s2">&#34;src&#34;</span><span class="p">,</span> <span class="s2">&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/80a5366f89dfbd27ec46f669e0eac84.jpg&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>写法二：使用原本的事件监听方法：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">ele_img</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;click&#34;</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">src</span> <span class="o">=</span> <span class="nx">ele_img</span><span class="p">.</span><span class="nx">getAttribute</span><span class="p">(</span><span class="s2">&#34;src&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">ele_img</span><span class="p">.</span><span class="nx">src</span> <span class="o">===</span> <span class="s2">&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/80a5366f89dfbd27ec46f669e0eac84.jpg&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">ele_img</span><span class="p">.</span><span class="nx">setAttribute</span><span class="p">(</span><span class="s2">&#34;src&#34;</span><span class="p">,</span> <span class="s2">&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231005005911.png&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">ele_img</span><span class="p">.</span><span class="nx">setAttribute</span><span class="p">(</span><span class="s2">&#34;src&#34;</span><span class="p">,</span> <span class="s2">&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/80a5366f89dfbd27ec46f669e0eac84.jpg&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>写法三：将具体函数内容独立出去为 <code>ImgSwitch</code>，这里直接调用函数名</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">ele_img</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;click&#34;</span><span class="p">,</span> <span class="nx">ImgSwitch</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>也可放在匿名函数或者函数里：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">ele_img</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;click&#34;</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">ImgSwitch</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>例子三</strong> HTML 中添加 Button，CSS 对 Button 简单渲染，然后 JS 中添加输入事件，HTML 和 CSS 部分不在赘述。</p>
<blockquote>
<p>button 同样可以使用 onclick 事件来监听点击。</p>
</blockquote>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nx">ele_button</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;button&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">ele_button</span><span class="p">.</span><span class="nx">onclick</span> <span class="o">=</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">addUserName</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">addUserName</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">name</span> <span class="o">=</span> <span class="nx">prompt</span><span class="p">(</span><span class="s2">&#34;请输入您的姓名：&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">message</span> <span class="o">=</span> <span class="s2">&#34;欢迎您，&#34;</span> <span class="o">+</span> <span class="nx">name</span> <span class="o">+</span> <span class="s2">&#34;/&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">localStorage</span><span class="p">.</span><span class="nx">setItem</span><span class="p">(</span><span class="s2">&#34;name&#34;</span><span class="p">,</span> <span class="nx">name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">Heading</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="nx">message</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">localStorage</span><span class="p">.</span><span class="nx">getItem</span><span class="p">(</span><span class="s2">&#34;name&#34;</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">Heading</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="s2">&#34;欢迎您！&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">Heading</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="s2">&#34;欢迎您，&#34;</span> <span class="o">+</span> <span class="nx">localStorage</span><span class="p">.</span><span class="nx">getItem</span><span class="p">(</span><span class="s2">&#34;name&#34;</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&#34;/&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>这里主要是 prompt 可以唤出一个输入框，将信息输入 name 中</li>
<li>LocalStorage 将信息存到本地的浏览器中</li>
<li>然后最后的判断做一个初始化，如果浏览器中缓存有相关信息就直接输出，否则输入一个 default 值。</li>
</ul>
<p>如何<strong>写入浏览器的缓存</strong>也是后续很重要的一个事情，有存储对于多次页面交互来说十分关键。</p>
<p>后续章节 [[tmp/LearnWeb18-JS03-事件]] 会更详细的讲解事件相关的 JS 代码。</p>
<h3 id="loop-循环">Loop 循环</h3>
<table>
  <thead>
      <tr>
          <th style="text-align: left">TYPE</th>
          <th>A</th>
          <th>B</th>
          <th>C</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: left">循环范式</td>
          <td>for</td>
          <td>while</td>
          <td>do&hellip;while</td>
      </tr>
      <tr>
          <td style="text-align: left">常见关键词</td>
          <td>break</td>
          <td>continue</td>
          <td></td>
      </tr>
  </tbody>
</table>
<h4 id="for-循环">For 循环</h4>
<blockquote>
<p>FOR 循环的方式和 cpp 比较相似，可以对列表直接进行循环，列表元素可以是 Obj 和 Dom 元素等。</p>
</blockquote>
<p>普通的 FOR 循环方式：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">fruits</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;apples&#34;</span><span class="p">,</span> <span class="s2">&#34;bananas&#34;</span><span class="p">,</span> <span class="s2">&#34;cherries&#34;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">fruits</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">	<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">fruit</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>类似 auto 的循环变体：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">fruits</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;apples&#34;</span><span class="p">,</span> <span class="s2">&#34;bananas&#34;</span><span class="p">,</span> <span class="s2">&#34;cherries&#34;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="kr">const</span> <span class="nx">fruit</span> <span class="k">of</span> <span class="nx">fruits</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">fruit</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>例如下面的方式对 Dom 进行循环清空内容</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">resetParas</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelectorAll</span><span class="p">(</span><span class="s2">&#34;.resultParas p&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="kr">const</span> <span class="nx">resetPara</span> <span class="k">of</span> <span class="nx">resetParas</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">resetPara</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这里的 <code>querySelectorALL</code> 是 <code>querySelect</code> 的延伸，找出.resultParas 中所有的 p 元素，并将其放于列表之中。</p>
<blockquote>
<p>focus 是 input 的一个可用属性函数，可以将光标聚焦于输入框中，方便控制和减少用户的操作，善用 focus 切换关注的输入框能提升交互体验。</p>
</blockquote>
<p>JS 中 Continue 和 Break 的用法也和其他的语言一致，分别是跳过单词循环和跳出当前循环。</p>
<h4 id="while-循环">While 循环</h4>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">initializer</span>
</span></span><span class="line"><span class="cl"><span class="k">while</span><span class="p">(</span><span class="nx">condition</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// code run in while.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">  <span class="c1">// condition change statement. eg:
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">i</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="dowhile-循环">do&hellip;while 循环</h4>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">initializer</span>
</span></span><span class="line"><span class="cl"><span class="k">do</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// code run in do ... while
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  
</span></span><span class="line"><span class="cl">  <span class="c1">// condition change statement. eg:
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">i</span><span class="o">++</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="k">while</span><span class="p">(</span><span class="nx">condition</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>两种形式的 while 的区别就是在执行循环之前还是之后，判断当前是否满足条件。</p>
<h3 id="condition-条件语句">Condition 条件语句</h3>
<p>JS 条件语句的语法和 CPP 基本一致，下面是 JS 的条件语句单元</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="nx">condition</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">condition</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span> <span class="p">{}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>JS 中的与或非运算符如下：</p>
<table>
  <thead>
      <tr>
          <th>Title</th>
          <th>与</th>
          <th>或</th>
          <th>非</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Operator</td>
          <td>&amp;&amp;</td>
          <td>||</td>
          <td>!</td>
      </tr>
  </tbody>
</table>
<p>条件语句中往往还会涉及到 <code>switch</code> 语句，对于需要很多个 <code>if else</code> 的场景，可能会更方便一些，<code>switch</code> 的模板如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="k">switch</span><span class="p">(</span><span class="nx">expression</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="nx">value1</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">		<span class="nx">LOGIC1</span>
</span></span><span class="line"><span class="cl">		<span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="nx">value2</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">		<span class="nx">LOGIC2</span>
</span></span><span class="line"><span class="cl">		<span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		
</span></span><span class="line"><span class="cl">	<span class="k">default</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">		<span class="nx">LOGIC3</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><code>default</code> 不需要使用 <code>break</code> 跳出，如果没有hit 任何的value，就执行默认的逻辑块，<code>switch</code> 很多时候用于选择页面的选择框情况。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;weather&#34;</span><span class="p">&gt;</span>选择今天的天气：<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">select</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;weather&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">option</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;&#34;</span><span class="p">&gt;</span>--作出选择--<span class="p">&lt;/</span><span class="nt">option</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">option</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;sunny&#34;</span><span class="p">&gt;</span>晴天<span class="p">&lt;/</span><span class="nt">option</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">option</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;rainy&#34;</span><span class="p">&gt;</span>雨天<span class="p">&lt;/</span><span class="nt">option</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">select</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;&lt;/</span><span class="nt">p</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">select</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;select&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">para</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;p&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">select</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;change&#34;</span><span class="p">,</span> <span class="nx">setWeather</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">setWeather</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">choice</span> <span class="o">=</span> <span class="nx">select</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">switch</span> <span class="p">(</span><span class="nx">choice</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="s2">&#34;sunny&#34;</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">      <span class="nx">para</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="s2">&#34;阳光明媚。穿上短裤吧！去海滩，或公园，吃个冰淇淋。&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="s2">&#34;rainy&#34;</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">      <span class="nx">para</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="s2">&#34;外面下着雨；带上雨衣和雨伞，不要在外面呆太久。&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">default</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">      <span class="nx">para</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>对于一些简单的选择和条件判断的情况，也可以使用三元运算符来实现，和 CPP 一样是问号冒号表达式吧，从下面的 case 可以看出三元表达式非常时候在类似明亮和暗黑主题切换的场景中。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">select</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;change&#34;</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">select</span><span class="p">.</span><span class="nx">value</span> <span class="o">===</span> <span class="s2">&#34;black&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="o">?</span> <span class="nx">update</span><span class="p">(</span><span class="s2">&#34;black&#34;</span><span class="p">,</span> <span class="s2">&#34;white&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">:</span> <span class="nx">update</span><span class="p">(</span><span class="s2">&#34;white&#34;</span><span class="p">,</span> <span class="s2">&#34;black&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script>]]></content:encoded>
    </item>
    <item>
      <title>《定投十年财务自由》读书笔记</title>
      <link>https://aikenh.cn/posts/%E5%AE%9A%E6%8A%95%E5%8D%81%E5%B9%B4%E8%B4%A2%E5%8A%A1%E8%87%AA%E7%94%B1%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/</link>
      <pubDate>Tue, 12 Mar 2024 23:05:46 +0000</pubDate>
      <guid>https://aikenh.cn/posts/%E5%AE%9A%E6%8A%95%E5%8D%81%E5%B9%B4%E8%B4%A2%E5%8A%A1%E8%87%AA%E7%94%B1%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-summary&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Summary&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;本篇读书笔记主要记录书中一些投资理财相关的概念、一些思维方式、一些典型的策略等等，用于自己后续理财的基础。&lt;/p&gt;

&lt;/blockquote&gt;
&lt;p&gt;“投资理财越早开始越好，无需拘泥于启动资金的多少，时间才是投资理财中最重要的增长因子”。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;财务自由&#34;&gt;财务自由&lt;/h2&gt;
&lt;h3 id=&#34;需要多少钱才能财富自由&#34;&gt;需要多少钱才能财富自由&lt;/h3&gt;
&lt;p&gt;4%法则（William Bengen）：通过投资一组资产，每年从退休金中提取不超过 4%的金额用来支付自己的生活所需，那么直到自己趋势，退休金都花不完。&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>本篇读书笔记主要记录书中一些投资理财相关的概念、一些思维方式、一些典型的策略等等，用于自己后续理财的基础。</p>

</blockquote>
<p>“投资理财越早开始越好，无需拘泥于启动资金的多少，时间才是投资理财中最重要的增长因子”。</p>
<hr>
<h2 id="财务自由">财务自由</h2>
<h3 id="需要多少钱才能财富自由">需要多少钱才能财富自由</h3>
<p>4%法则（William Bengen）：通过投资一组资产，每年从退休金中提取不超过 4%的金额用来支付自己的生活所需，那么直到自己趋势，退休金都花不完。</p>
<p>因此如果每年需要 40w 的开销，那么就需要超过 1000w 的资产来实现一个比较稳定的财富自由，按照自己每年的消费可以进行简单的换算。</p>
<h3 id="如何避免财富缩水">如何避免财富缩水</h3>



  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>财富缩水主要的原因就在于通货膨胀，对通货膨胀有所了解才能更好的从通货膨胀中保护自己的财富。</p>

</blockquote>
<p>很多时候通货膨胀看的是 CPI(居民消费价格指数)，最近几年国内的 CPI 同比增长一年为 2%~3%，也就是说物价每年上涨 2%~3%，但是实际上只看 CPI 是不够的，这是因为 CPI 实际上仅包含了必需消费，而如果要保证生活质量的水平不变，需要跑赢的是&quot;可选消费通货膨胀率&quot;。</p>
<p>这是因为任何一个社会，优质的教育和医疗资源的价格增长速度是比较显著的高于 CPI 的，因此可选消费指数才是我们要跑赢的目标。而这个增长速度则通常和 M2 的增长速度相关。</p>
<blockquote>
<p>M2 是广义货币的量，代表社会广义货币的增长速度，最近三年的同比大概在 8%~9%，但是该指数并非完全和可选消费指数相等同。</p>
</blockquote>
<p>综合而言，我们通常需要考虑的膨胀指数应该介于 CPI 和 M2 增速之间，因此资产增值的速度应该在 3%~9%之间，才能避免财富缩水，如果考虑一些不稳定时局的原因，可能还要存一些避险资产例如黄金。</p>
<p>通常来说，只要长期投资债券基金（包括相关的理财产品）是可以跑赢 CPI 的，债券通常的长期平均收益都在 6%上下，但若想要获得更高的收益可能就得上股票这种高风险高收益的了。</p>
<h2 id="定投">定投</h2>
<p>巴菲特：“通过<strong>定投指数基金</strong>，一个什么都不懂的业余投资者，往往能够战胜大部分的专业投资者”</p>
<p>这里涉及到的两个概念：定投、指数基金后面均会有所解释，首先简单解释定投：</p>



  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p><strong>定投</strong>实际上就是定期投入的意思，定期的将资金转入某个能产生现金流的金融资产，五险一金实际上就是一种定投，每一个周期按照一定的规则投入一定的资金进行投资。</p>

</blockquote>
<p><del>定投能起到的一些小的作用是（这两点上我个人并不认为是什么作用）：①强制储蓄，克制穷人思维。②保值增值，避免人力资产贬值的风险。</del></p>
<p>定投还有另外一个特性，是我认为定投最重要的一点：<strong>定投是一种被动投资理念，其希望我们不要去预测市场</strong>，因此坚持定投与我而言，我认为其最大的作用在于能够<strong>摒弃人的主观判断</strong>，抛弃自己能够准确判断短期市场涨跌的想法，来选择一种更稳妥的方式进行投资。</p>
<h3 id="定投要投资什么">定投要投资什么</h3>



  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>定投要投能带来现金流的资产</p>

</blockquote>
<p>这里我觉得资产这个说法还是比较容易混淆的，应该说定投要做能够带来现金流的投资，不过为了统一说法，后面还是用资产来进行说明；能够带来现金流则指的是，能够产生收益，产生额外的金钱，这就是现金流，比较拗口举个例子（以资产：现金流的形式）：</p>
<ul>
<li>债券：每年产生的利息，利息</li>
<li>房地产：租金</li>
<li>工作（我们这个人力）：工资</li>
</ul>
<p>无法产生现金流的产品也是有的，例如：珠宝、艺术品、古董、甚至黄金（避险资产，特指经济和市局稳定下的黄金）</p>
<h3 id="有什么可以选择的投资项目">有什么可以选择的投资项目</h3>
<p>普通投资者在日常生活中能投资的产品按照性质通常可以分为：<strong>货币</strong>、<strong>债券</strong>、<strong>股票</strong>三类，可以选择直接投资这些资产，但是不同的品种的投资门槛有较大的差别，例如货币市场可能需要 500w 以上才能进入，部分股票一股的金额也比较高，部分债券的门槛也比较高。</p>
<p>所以通常而言普通投资者这都会通过一些间接的金融产品来接触这三类金融产品，即：<strong>银行理财产品</strong>、<strong>股票基金</strong>；</p>
<p>基金大部分只需要几十几百元即可投资，银行理财可能略高一些，但是大多都是普通投资者可以接受的。简单说明一下两者的特点</p>
<p>银行的产品分为典型的<strong>储蓄</strong>，和<strong>理财</strong>：</p>
<ul>
<li>储蓄：活期/定期存储产品，利率较低，但是风险极低，长远来看也算是定存</li>
<li>理财：类似定期存储（周月年）但是有一些不一样的特点，①门槛相对较高②在特殊时点收益高（考核）③小银行的收益一般比大银行高（吸引用户）
<ul>
<li>收益：国有&lt;商业&lt;城商、农商行&lt;信用社</li>
<li>风险与收益相反</li>
<li>城商级别就有一定的风险了（大城市除外）</li>
<li>一般期限越长收益率越高</li>
</ul>
</li>
</ul>
<blockquote>
<p>通常而言，银行理财产品主要投资的为债券类品种，本身长期收益率在 4%~6%之间，比储蓄相对较高，但是不会高太多。</p>
</blockquote>
<p><strong>基金</strong>则是我们最常接触到的投资工具，实际上就是基金公司给出一种投资方案，大家一起集资进行投资，通过拼团的方式，使得众多普通人能够以较低的门槛一起参加哪些门槛较高的投资活动，并基于该方案一损俱损一荣俱荣。</p>
<p>基金投资有以下的<strong>特点</strong>：</p>
<ul>
<li>有基金经理专门管理（实际上理财产品发行商都会有），因此无需频繁操作</li>
<li>可以分散风险（资金池庞大，足够实现多种配比，实现个体户难以实现的分散投资）</li>
<li>降低投资门槛</li>
</ul>
<p>接下来我们先对基金，也就是我们即将投资的内容要有更清楚的认知后才能更好的去选择和投资。</p>
<h2 id="基金">基金</h2>
<h3 id="基金的交易方式">基金的交易方式</h3>



  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>对于普通投资者来说，常见的交易基金的方式主要有两种：申购赎回和买入卖出</p>

</blockquote>
<p>申购基金：向基金公司购买基金份额（也就是用钱入场）
赎回基金：基金公司用钱购回我们手上的基金份额（也就是拿钱走人）</p>
<p>这种申购&amp;赎回的流程，这里的<strong>交易对象是基金公司</strong>。而买入卖出就像是“二手交易市场”，该二手交易市场是由政府专门成立和监管的，任何人不想要的基金或者想要购买特定基金的也可以从该市场中购买，并不一定要从基金公司手上购买，这里的<strong>交易对象是个人</strong>。因此申购&amp;赎回会导致基金的份额发生变化，而买入&amp;卖出则不会；</p>
<blockquote>
<p>这里的二手交易市场也就是上海证券交易所 &amp; 深圳证券交易所等地方，很多基金可以在此处交易和买卖。</p>
</blockquote>
<p>这也就衍生出了场内基金和场外基金的概念：</p>
<ul>
<li>场内基金: 只能从基金公司申购基金</li>
<li>场外基金: 除了从基金公司申购，还能去证券交易所进行买入卖出</li>
</ul>
<h3 id="基金的分类和基本概念">基金的分类和基本概念</h3>
<p>基金的类别较为广广泛，常见的有：公募，私募，养老，社保等，普通投资者和我们后续进行分析的都是公募基金。</p>
<p>按照<strong>投资的方向</strong>也可以对基金做一个分类：</p>
<ul>
<li>股票基金：&gt;80% 股票，通常的指数基金也属于股票基金，分级基金/母基金大多是指数基金。</li>
<li>债券基金：&gt;80%债券</li>
<li>混合基金：股票债券货币的组成较为灵活，大多保本基金为混合基金</li>
<li>货币基金：类似活期储蓄</li>
</ul>
<p>如果按照投资的理念，则分为：<strong>主动型基金</strong>和<strong>被动型基金</strong>：主动型基则是基金经理自己选择调整构成，而被动型基金是根据某个指数或者规则来被动确定和调整基金的构成，指数基金即为一个典型的被动基金，按照事先规定的指数规则来选股。</p>
<blockquote>
<p>因为规则的一致，同一个指数的不同基金的表现都会大差不差的。</p>
</blockquote>
<p>按照销售的渠道，则分为：场内基金和场外基金；</p>
<p>按照募集对象，可以分为公募基金和私募基金：</p>
<blockquote>
<p>公募和私募的区别就在于是否公开招募，私募一般门槛都要大几百万，公募，公开招募大多门槛较低。</p>
</blockquote>
<p>按照基金是否开放，可以分为：开放式基金和封闭式基金：</p>
<blockquote>
<p>开放基金持续接受申购赎回，基金的份额会发生变化；
封闭基金设置好确定的基金份额，不会过多变化，在结束了募资进入封闭期后，不会接受申购和赎回，如果想要只能去证券交易所购买</p>
</blockquote>
<p>早期的时候大多都是封闭式基金，现在&amp;我们将要考虑的也主要都是开放式基金了，介绍完了交易方式和基金种类后，我们就可以考虑如何去选择基金做投资了，在选择中我们主要按照投资的方向去做决策，接下来就介绍三类基金的一些特点。</p>
<h3 id="基金的选择">基金的选择</h3>
<blockquote>
<p>下面这些基础知识后面可以去《指数基金投资指南》中补充，这里主要是一些简单的基本概念介绍。</p>
</blockquote>
<h4 id="货币基金">货币基金</h4>
<p>货币基金是专门投资那些安全又具有很高流动性的货币市场工具的基金，其主要包括：期限小于1年的短期国库券、政府公债、大额可转让定期存单、商业本票、银行承兑汇票。</p>
<p>其主要针对大资金的投资者开放，且大多具备高安全性和流动性的特点，因此<strong>非常适用于短期资金的打理</strong>。</p>
<p>如何挑选货币基金？</p>
<p>货币基金没有申购赎回费，但是货币基金会收取<strong>销售服务费、管理费、托管费</strong>，很直观的在购买货币基金的时候需要注意该费率之间的不同，越低越划算，一般而言，各类货币基金中，B 类货币基金的费率是相对较低的，以往是因为门槛高没有普及开，现在也有一些降低了门槛的 B 类货币基金。</p>



  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>货币基金的主要特点是：几乎不会亏损，买卖方便，长期收益较低，适合打理短期零钱。因此购买货币基金的时候，主要注意费率之间的不同。</p>

</blockquote>
<h4 id="债券基金">债券基金</h4>
<p>债券基金是以债券为主要投资对象的基金，主要投资的对象为：国债、金融债、企业债等固定收益类金融产品。虽然货币基金也可以投资债券，但是一般都需要剩余期限在 397 天以内，而债券基金没有上述的限制，两者实际上有所类似，可以认为<strong>货币基金更针对的是短期的品种，而债券基金会考虑稍微长期一些的场景</strong>。</p>
<p>债券基金有申购赎回费用，其又可称为“<strong>固定收益品种</strong>”，债券基金追求的是更加固定的收入，其周期相较货币基金更长，当时收益也略高于货币基金，风险系数也较小。可以作为一种定期存款的替代品，但是相比定期存款，其利息高些，但是不保证&amp;不承诺收益。</p>
<p>考虑纯债基金，主要可以分为两类：短期债基（相比货币基金投资范围更广，但是近几年短期的债基都被货币基金取代因而品种少），中长期债基（场内场外都有）主要追踪的都是国债和城投债指数，各家基金公司通常都有历史业绩好表现稳定的长期债基，其同质化也相对较高，不像股基的收益方差很大。</p>
<p>==债券基金的风险来源==</p>
<p>债券基金收益既然比货币基金要高一些，风险确实也是相对要高的，其风险来源主要是<strong>市场利率的变化</strong>，因为债券的价格和市场利率是负相关的：利率下降，债券的价格就会上升，回报就会更好。</p>
<p>可以理解为，市场的利息上去了，那么人们会倾向于存款而不会购买债券，供需关系变化后就会导致价格的下跌，那么相对专业一点：</p>



  
  

<blockquote class="alert-blockquote alert-quota">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Quota</span>
  </p>
  <p>一般来说：加息周期，利率上升，债券基金表现不会太好；降息周期，利率下降，债券基金则会表现不错。假如利率变动 1%，比起短期债基，长期债基受到的影响要更大，跌幅或涨幅都要更高</p>

</blockquote>
<p>如何购买和选择债券基金？主要的 tips 就以下的两点：</p>
<ul>
<li>利率低位选短期债基，利率高位选长期债基</li>
<li>选好品种后，出现浮亏可以加仓拉低成本</li>
</ul>
<p>但是更为重要的是要判断长期利率的走势：&ldquo;如果利率处于历史走势的底部，那未来的下降空间就不大，但有较大的上升空间。如果利率处于历史走势的顶部，则有很大的下降空间。&rdquo;</p>
<p>👍 可以使用历史平均周期的利率来进行估算：&ldquo;过去十几年，十年期国债利率的中位数是 3%~3.5%。以这个作为标准，当利率低于 3%的时候，也就是利率处于低位的时候，建议大家选择短期债券基金，或者干脆直接选择货币基金。当利率高于 3.5%的时候，建议大家选择长期债券基金。&rdquo;</p>
<blockquote>
<p>一般来说，债券基金的投资风险不高，但在持有过程中收益也是很有可能下跌的。市场利率变化是有周期性的，不会一直上升或下降，波动周期也是比较短的，3~4 年一轮。如果我们持有的债券基金出现了账面浮亏的情况，可以通过加仓把成本降下来。用这种方式，投资债券基金就很容易赚到钱了。</p>
</blockquote>
<h4 id="股票基金">股票基金</h4>
<p>股票基金顾名思义是以股票为主的基金，其收益率和风险都是最大的，根据股价的走势，可能大赚特赚也可能一亏到底，但是股票基金的长期收益通常是三种基金中最高的(如果选择正确的话)。</p>
<p>一般选择定投的就是股票基金，而且定投的主力是其中的<strong>指数基金</strong>（被动型基金，上述有提到），指数基金也是巴菲特建议普通投资者选择的基金，（他自己最经常推荐的就是<strong>低成本的标普 500</strong>）</p>
<p>指数基金的优势？</p>
<ol>
<li>基于市场指数进行变化，有新陈代谢的活性</li>
<li>能够长期上涨：&ldquo;巴菲特也提到，买指数基金就是买国运。只要相信国家能继续发展，指数基金就能长期上涨，我们就能分享国家经济增长的收益。&rdquo;</li>
<li>费用低廉：指数基金的托管费和管理费相比主动基金明显更低</li>
</ol>
<p>同时其能够规避：</p>
<ol>
<li>市场黑天鹅风险，因为指数基金投资通常几十上百只股票，不会因为个体崩盘，并会定期调整</li>
<li>本金永久损失的风险，指数通常下跌也有极限</li>
<li>制度风险，确定的规则，开放的选股，不会阴沟里被人坑</li>
</ol>
<h4 id="总结">总结</h4>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240315190114.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240315190114.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240315190114.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<hr>
<ul>
<li>短期存储的工具（货币类工具）：银行储蓄和货币基金中货币基金相对更合适，收益也会更高一些，其基本上长期稳定的小幅度上涨。</li>
<li>中长期保障性存储工具：银行理财产品和债券基金。这两类的投资收益不相上下，但大部分银行理财产品在持有的时候看不到波动浮亏，投资者可能会更心安一些，其中银行理财产品的底层大多就是债权类基金，其收益相对货币更高，但是存在波动风险，严重时甚至高达 1x%，但只要战线够长基本都能盈利。</li>
<li>激进类资产（股票类工具）：高风险高收益产品，也是唯一在获得收益后能够对抗通胀的产品（if 通胀进行中），波动大。</li>
</ul>
<h2 id="指数基金">指数基金</h2>
<blockquote>
<p>指数的命名，名称中的数字通常代表其会挑选多少只股票。</p>
</blockquote>
<p>不限制投资行业的指数就是<strong>宽基指数</strong>，而有的指数在投资的时候会限制行业，例如消费行业指数，这种就是<strong>行业指数</strong>，行业指数受到行业影响比较大，初学者优先还是选择宽基指数。</p>
<p>指数基金的配置方式：市值加权和策略加权；</p>
<p><strong>市值加权</strong>即股票的市值越高在指数中的占比就越高，<strong>策略加权</strong>则是按照别的方式来决定个股权重（smart-beta）指数，由于策略加权的策略多样性，导致在不同市场（牛/熊）中各个基金也能有不同的表现，因此结合多种不同策略的特点，就能在不同的市场环境下更好的投资。</p>
<p>选择对应的基金时，遵循以下的两个思路：①寻找费用最低、误差最小的品种；②寻找有特色的增强型指数基金，不过如何增强相对不透明，相比于普通基金更具风险。常见的宽基指数有以下这些：</p>
<p>A 股：<strong>沪深 300</strong>（最具规模和代表性）、中证 500（<strong>最容易获得超额收益的指数</strong>）（利用其不理性的涨跌）、创业板指数（整体盈利较低、不稳定）（容易暴涨暴跌）；</p>
<p>港股：</p>
<ul>
<li>恒生指数（最具代表性，代表的是港股的蓝筹股）-&gt; 盈富基金（恒生指数基金的最佳选择）、H 股指数（内地注册，香港上市，用港币交易的股票）</li>
<li>香港中小指数（主要投资的是 H 股和红筹股，）-&gt; LOF(上市型开放式基金)</li>
<li>风险：老千股</li>
</ul>
<p>美股：主要的有以下两个著名指数</p>
<ul>
<li><strong>纳斯达克指数</strong>（NDX）（纳斯达克规模最大的 100 家企业）</li>
<li><strong>标普 500 指数</strong>（带主观判断的蓝筹股指数）：大公司 90%，中型公司 10%，入选标准为：行业领导者，ROE（净资产收益率）更好的入选。
<ul>
<li>更宽、更稳，以消费、医药、科技等周期性产业的占比更高。</li>
<li>能够代表美股市场的基准收益，</li>
<li>属于美元资产，可以分散风险</li>
</ul>
</li>
</ul>
<h3 id="策略加权指数基金">策略加权指数基金</h3>
<p>上面这些指数主要都是基础的市值加权的宽基指数基金，这类品种具备长期的，与国家经济发展相关的半稳定性，故而其通常是各个股票市场上的主力品种。除了这些基于市值加权指数基金外，通常还有两类基金比较小众且长期投资收益更好。</p>
<ul>
<li>策略加权指数基金：采取某种投资策略来挑选股票</li>
<li>长期优秀的行业指数基金：有的行业本身的盈利能力相对出色，如当下的 IT</li>
</ul>
<p>所有的策略指数中，最常见最有影响力的主要是：红利指数、基本面指数、价值指数、低波动指数。</p>
<h4 id="红利指数持股收息的最佳选择">红利指数：持股收息的最佳选择</h4>



  
  

<blockquote class="alert-blockquote alert-quota">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Quota</span>
  </p>
  <p>股票是会发放股息的，也就是现金分红，业绩比较好的公司，每年会从净利润拿出来一部分，以现金分红的形式回馈股东。</p>

</blockquote>
<p>红利指数，按照股息率来决定个股的权重，因为公司能持续发放股息，也就说明其财务和盈利状况较好，因此，能分红的股票往往也是一个好的选择。</p>
<p>四个主要的红利指数：上证红利指数、中证红利指数、深证红利指数、红利机会指数，他们分别有着不同的特点，但是红利指数通常有一些共同的优点：</p>
<ul>
<li>高股息率：<strong>在熊市更有优势</strong>，在熊市中是非常不错的优势；</li>
<li>波动较低：由于企业的经营情况要好才能发出股息，因此相对而言比较稳定；</li>
<li>提供分红现金流：有的红利指数基金会将基金分红的形式发放给基金持有者</li>
</ul>
<p>也有一些共同的缺点：有一些股票会因为短期的大幅盈利而大比例分红，就可能会入选红利指数，但是这种短期大涨并不会持续，就会影响指数的长期分红能力，影响其稳定性，但整体瑕不掩瑜。</p>
<h4 id="基本面指数">基本面指数</h4>
<p>基本面指数属于质量指数，从上市公司的经营质量的角度去挑选股票，其不看市值，只看基本面指标：营业收入（过去 5 年的营业收入平均值）、现金流（过去 5 年现金流的平均值）、净资产（定时调整的净资产）、分红（过去 5 年分红的总额）。</p>
<p>而国内最出名的基本面指数为：中证基本面 50 指数；</p>
<p>基本面指数相比普通的指数，最大的好处是收益会相对更高一些，但是基本面指数在不同时间段的表现显示其<strong>在熊市跑赢市场更多一些</strong>，在各国的熊市中，基本面都能跑赢标普 5.8%，在牛市中跑赢标普 0.7%左右，平均下来多出了 2%~3%的年华收益率。</p>
<p>基本面指数对应的指数基金有：基本面 50、深证基本面 60/120 基本面 400 等，不过大部分规模都太小，不适合投资。</p>
<blockquote>
<p>红利指数和基本面指数，在熊市相对更抗跌一些，一方面其现金流吸引大家长期持有股票，另一方面，熊市下跌过程中分红投入，也可以托底股价，所以这也是熊市中更好的选择，这两类都是长期不错的指数。</p>
</blockquote>
<h4 id="价值指数">价值指数</h4>
<p>基本面指数使用 4 个基本面指标的规模大小来加权，价值指数相似使用四个估值指标来进行筛选：市盈率、市净率、市现率、股息率。</p>
<ul>
<li><strong>市盈率</strong>=公司市值/公司盈利</li>
<li><strong>市净率</strong>=公司市值/公司净资产</li>
<li><strong>市现率</strong>=公司市值/现金流量</li>
<li><strong>股息率</strong>=现金分红/公司市值</li>
</ul>
<p>通常对于同一个股票品种来说，市盈率、市净率、市现率越低，股息率越高，这个品种的投资价值也会越高，价值指数就是用的这种策略。</p>
<p>其走势，特征，收益和上述的红利和基本面指数也差不多，不过前两年在国内的数量不多，目前主要就沪深 300 指数。</p>
<h4 id="低波动指数">低波动指数</h4>
<p>低波动指数是挑选市面上波动率最低的一批股票。这里的波动率，说的是股票每天涨跌幅的标准差，有点龟兔赛跑的味道了，该指数有以下特点</p>
<ul>
<li>波动率最低的 150 只股票</li>
<li>波动率加权</li>
<li>避免集中于某个行业，对行业股票数量进行限制</li>
</ul>
<h4 id="选择策略加权指数基金">选择策略加权指数基金</h4>
<p>策略加权指数基金是很不错的，因为其收益往往由于基本的宽基指数基金，以有效加权指数基金为定投品种，可以帮助我们在定投的过程中提高收益，但是策略加权指数基金也有一些缺点：</p>
<ul>
<li>资金容量不大：容纳不了太多基金（相对，影响不了个人)</li>
</ul>
<h3 id="行业指数基金">行业指数基金</h3>



  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>实际上就是选择一个行业方向去进行投资，相比于宽基指数而言，行业的难度和风险就会更高一些，因为单独国家的发展可能是向前的，但某个行业却不一定，不过行业指数能够较好的丰富投资的品类，作为宽基指数的补充。</p>

</blockquote>
<p>股票的涨跌主要有两个方面构成，一个是企业发展情况的事实，第二个则是投资者的信心和共识，事实作为信心的来源，信心和共识则是股票涨跌的原因。因此在做这种选择判断的时候，要基于事实、舆论、发展趋势去做基本的判断。</p>
<p>从供需关系和长期发展的关系来看，可以脱离时代背景，长盛不衰的行业（更容易赚钱）主要集中在：消费和医药行业，因为无论处于什么时局，健康和日常消费都是作为一个人类不可或缺的，这里的供需关系是长期稳定和健康的。</p>
<p><strong>消费行业</strong>主要包括：饮料、酒、农副食品等，其中主力为食品饮料行业，这也是巴菲特比较推崇的一类，如可乐，稳定且可长期发展不会有太大的变化。</p>
<p>A 股中代表性的消费指数主要是：上证消费指数、上证消费 80 指数、中证消费指数、全指消费指数；也有一些食品饮料的指数。</p>
<p><strong>医药行业</strong>的两大优点：长牛&amp;避险，和消费行业一样，人都离不开生老病死，因此这个需求是比较稳定的，不过医药行业会有政策的风险，比如政府会限制医药行业的收益，来降低国民的医疗支出，和政府医保的财政支出，但是仍然瑕不掩瑜是一个比较优秀的行业。</p>
<p>A 股中相关的医药指数还是比较多的，300 医药指数，500 医药指数，中证医药指数，全指医药指数，中证医药 100 行业指数，投资的时候要选择规模大一些的，上面的指数不是都适合投资。同时要考虑规避&amp;承担黑天鹅风险的。</p>
<p><strong>可选消费行业</strong>：高档手机、汽车、大家电等；其特点为：①需求弱于必需消费、有一定的周期性 ②收益于人口红利，特别是人均消费金额的提升；③具备更新换代的特性</p>
<p>那么怎么去选择行业指数呢？</p>
<p>⭐🌟相比于宽基指数，这些行业指数会有额外的风险，推荐是定投的时候可以以宽基策略加权指数基金为主，然后以优秀行业指数基金为辅去做组合，稳健的基金作为投资主力，然后使用一些优秀的行业基金来博取超额收益。</p>
<p>挑选过程中记得：<strong>规模合适</strong>、<strong>费用低廉</strong>、<strong>追踪误差小</strong>，下面会详细的将讲一下具体的标准和选择方式。</p>
<h2 id="基金的投资和选择">基金的投资和选择</h2>
<p>这里首先讲一个最重要的问题：指数基金会不会跑路（捐款逃跑）、暴雷（类似 P2P 钱无法周转，导致无法支付投资者的本金和利息）</p>
<p>指数基金不会跑路，原因如下</p>
<ul>
<li>公募基金公司的门槛很高（实缴注册资本&gt;1e，股东资产达标，3 年内无任何不良信用）</li>
<li>公募基金都有托管人，（资金托管于第三方银行或者券商），基金公司没有卷款潜逃的权利和能力</li>
<li>证监会和基金协会严格监管，包括投资和风险控制流程。</li>
</ul>
<p>暴雷的可能性也极小，原因如下：</p>
<ul>
<li>公募基金可以投资的对象受到了严格的限制，不得投资这种非标准的金融产品</li>
<li>鸡蛋不是放在一个篮子里，通常会有多个产品和股票的分散投资。</li>
<li>但是存在大涨大跌的风险。</li>
</ul>
<h3 id="基金销售平台倒闭了怎么办">基金销售平台倒闭了怎么办</h3>
<blockquote>
<p>这里的基金销售平台指：蚂蚁财富、天天基金、蛋卷基金之类的，其注册成本和资金相对都比较庞大，倒闭的风险较小，这里不再赘述。</p>
</blockquote>
<p>😀核心是：基金销售平台并不会持有我们的基金，其只负责销售基金，基金最终是到了基金公司的托管账户中，平台与我们的资金是分割的，即使平台倒闭了，也可以在基金公司找到我们购入的基金份额。</p>
<p>作为平台而言，其运作成本并不高，通常并不会出现这种倒闭的情况。</p>
<h3 id="基金公司倒闭了怎么办">基金公司倒闭了怎么办</h3>
<p>像风险和成本就不再说了，和平台一样是低成本运作的公司，如果真的倒闭了，会提前走入清盘流程，</p>
<h3 id="基金规模太小的不要选">基金规模太小的不要选</h3>
<blockquote>
<p>一个基金所持有的股票、债券、现金的总市值，就是这个基金的规模，最好选择规模在 2e 元以上的</p>
</blockquote>
<p>如果一个基金的指数规模比较小，一个是有可能会有清盘的风险，且难以运作和保证收益的稳定性；清盘指的是，基金公司按照某个基金净值强制赎回（通常是基金亏本情况下停止运作），这可能会导致我们在亏损的状态下就中断了投资。清盘通常会留出一定的处理时间，但是对于我们长期投资的规划来说并不划算和方便。</p>
<p>另一个是固定费用的相对占比会比较高，以及资金的灵活性和流动性比较差，赎回的流程可能会更长。</p>
<h3 id="优先选择费用较低的基金">优先选择费用较低的基金</h3>
<p>事实上基金的收取费率对我们投资的收益的影响是很明显的，费率包含透明费率和不透明费率两种。下面会简单介绍一下：</p>
<p><strong>透明的费率</strong>主要是： 申购费、赎回费、管理费、托管费，下面给出一些基准参考</p>
<ul>
<li><strong>申购费</strong>：通常在 1%<del>1.5%左右，如果在银行购买就是这个价格，但是如果通过那些基金销售平台购买，通常会打一折。也就是在 0.1</del>0.15%，这对整体收益的影响就比较小了</li>
<li><strong>赎回费</strong>：赎回费在 7 天之内会有一个惩罚费率，1.5%，超过 7 天后通常在 0.5%左右，也还算比较合理，如果持有长期（1~2 年）赎回的费率会越来越低甚至免费</li>
<li><strong>管理费</strong>（每年扣除）：通常在基金报告中，大多数在 0.5%~0.8%</li>
<li><strong>托管费</strong>（每年扣除）：一般在 0.1%~0.2%</li>
</ul>
<p>后两者可能量化基金这种频繁操作的费率会相对高一些，其他的应该都得比较低才行，我们看到的基金净值通常都是扣除了管理费和托管费之后的。</p>
<p><strong>不透明的费率</strong>则有：分红税、印花税、交易佣金</p>
<ul>
<li>分红和印花税不是向我们个人收取的，而是国家和券商向基金机构收取的，但是调仓频率是固定的，所以相对换手率低一些，一般个人投资者不太考虑</li>
<li>交易佣金在基金的年报中也会有计算，基于不同换手率会有不同的交易佣金，指数基金的交易佣金大多在 0.1%~0.4%。</li>
</ul>
<p>不透明的这些费率通常是在取得整体收益之后，从基金的总额中扣除的，因此对于个人来说可能会看不到这部分的费率以及也不太考虑到这一块。</p>
<p>因此最主要的是要考虑管理费+托管费，申购赎回费，交易佣金（不好知道），购买的时候要注意这一块。</p>
<h3 id="优先选择追踪误差较小的基金">优先选择追踪误差较小的基金</h3>
<p>最终误差：指数基金特有的指标，是否能复刻，追踪好指数的表现（或者超过）这就能评估这个基金是否是我们想要追踪的指数效果。</p>
<p>怎么看：基金报告里面需要定期披露的指标，报告里可以看，也可以直接对比以下指数的数据就行。这个要看主要看两个方面：</p>
<ul>
<li>（一般更看重这个）基金份额净值增长率与业绩比较基准收益率的差值。</li>
<li>基金份额净值增长率标准差与业绩比较基准收益率标准差的差值。</li>
</ul>
<h2 id="结合估值进行投资选择">🔥结合估值进行投资选择</h2>
<p>为什么指数基金长期的收益不错，但是投资者通常都不赚钱，因此有&quot;七亏二平一赚&quot;的说法，这是因为投资者很多 <strong>&ldquo;追涨杀跌&rdquo;</strong> ，很多投资者，特别是新手投资者，往往都是在牛市入局的，在股票已经涨起来之后入场，在便宜的时候没有买入，后续的上涨空间就小了，反而更加容易下跌。指数基金也是一样的道理；</p>
<p>因此<strong>需要结合估值来判断指数基金是否是一个适合定投的状态</strong>，其存在自己的投资价值，我们要在其值得投资的阶段买入，如果在牛市大涨后再买入，就容易亏损，其实通常来说，在熊市反而更加值得坚持定投指数基金，短期大涨之后入局反而不适合。</p>
<p>因此我们要结合估值来判断当前是当前是否值得投资和入局，是熊市还是牛市。</p>
<h3 id="估值的基本理念">估值的基本理念</h3>
<blockquote>
<p>“估”是其第一个特点，鉴于股市是一个共识驱动的市场，就像我们无法计算出心理阴影面积一样，我们也无法为一个股票得出一个准确的股市价值，每个人对一个股票的心理预期是不同的。</p>
</blockquote>
<p>结合<strong>估值</strong>，对一个股票的价值进行估计，通过<strong>估值和当前市场价格的偏离</strong>，进行正确的策略选择，<strong>实现不同策略的价值投资</strong>是一个更为推崇的投资方法。</p>
<p>但是由于无法得到一个准确的估值，推荐结合格雷厄姆的“安全边际”理论来使用估值去做判断，也就是为估值留一个保守空间，再对该估值进行利用，这样的估值用起来就会更为安全。</p>
<h3 id="估值的方法">估值的方法</h3>
<blockquote>
<p>现在市场上流行的估值方法有几十中，但是通常分为：相对估值法和绝对估值法两类，这里我认为量化的核心可能就是结合深度学习算法来对股票做一个快速且短期的估值，并基于该估值计算出来的价格偏差进行短期且快速的偏差计算。</p>
</blockquote>
<p><strong>相对估值法</strong>：例如确定房价的时候和小区均价对比，核心在于<strong>参照物</strong>的选择，通过比较确定当前单位的估值。</p>
<p><strong>绝对估值法</strong>：一个投资品种在它生命周期内所能产生的现金流的折现值之和，就是这个品种的绝对估值。如果一个资产的现金流越明确，其越精准。</p>
<p>通常使用的时候会结合着来，绝对估值法这边的概念还不是很清楚，但是两者应该相互对照，最好是能得出一致的结论。</p>
<h4 id="估值过程中的要素选择">估值过程中的要素选择</h4>
<p>人类估值可以遵循&quot;奥卡姆剃刀原则&quot;，如无必要勿增实体，而如果打算使用 AI 进行估值，可以使用权重去做因子控制，然后根据学习出来的权重表来对因子做进一步的过滤选择。</p>



  
  

<blockquote class="alert-blockquote alert-quota">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Quota</span>
  </p>
  <p>上市公司的盈利、国家的政策法规、经济环境、企业的竞争、管理层的好坏、投资者的心理情况、资金面、汇率波动……每一个因素都有可能在短期里影响指数的走势。</p>

</blockquote>
<p>但是基于“约翰伯格”的总结，对指数基金影响最大的三个因素为<strong>市盈率</strong>、<strong>盈利</strong>、<strong>分红</strong>。+1 考虑企业的<strong>净资产</strong>。这几个是最常见的几个因素。要避免引入过多干扰要素来混淆估值过程。除了这几个以外，还有一些：市销率、市现率等指标，后续在做量化的时候要去了解这些个股投资指标。</p>
<p>指数基金作为股票的集合，相比于单个股票而言具备更高的稳定性和内在的指数规律联系，因此估值起来会更容易一些、成功率也更高。</p>
<h4 id="市盈率top1">市盈率：Top1</h4>
<p>🔴 首先抛出缺点：其不适合用于盈利变化大的品种上，也不适合强周期性品种，遇到金融危机和经济周期的底部会失效等。</p>



  
  

<blockquote class="alert-blockquote alert-think">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Think</span>
  </p>
  <p>市值率的缺点给了我们启发，再进行模型设计的时候，可以考虑结合 CrossAttention，对市场的情况（经济周期、熊/牛）、行业的特性，对不同的因子做不同的权重再控制，避免指标在不同的场景下的作用不一致。</p>

</blockquote>
<ul>
<li>静态市盈率：市值/上一年度财报的净利润</li>
<li>滚动市盈率：市值/最近四个季度财报的净利润，时效性更高一些，更推荐</li>
<li>动态市盈率：市值/预测未来一年的净利润，大多不用</li>
<li>席勒市盈率（CAPE）：市值/过去十年的净利润平均值，<strong>通常用于衡量一个股票市场的整体情况</strong>（需要<strong>历史更为悠久</strong>）</li>
<li>中位数市盈率：指数基金才有的指标，个股中没有；取 Set 中中位数的市盈率。</li>
</ul>
<p>其中中位数市盈率的作用可以额外的讲解一下：其可以避免市盈率计算中部分成分股被大多数绑架的情况（例如其他股票已经大涨，但是权重股票还没有大涨，使得指数处于低位，导致指数失真的情况），相对于普通的市盈率对于市场的变化更敏感。</p>
<p>中位数市盈率适用于：成分股的平均市值规模差别较大的情况，其作用会更明显，例如牛市时，如果中位数市盈率率先进入高估区域，说明大多数都已经涨起来了，这个时候要警惕后续下跌的风险。</p>
<h4 id="市净率top2">市净率：Top2</h4>
<p><strong>市净率</strong>：每股股价/每股净资产 == 账面价值，具体计算的时候使用如下公式：</p>
<div>
$$ 
PB=P/B
 $$
</div>
<p>其中 P 是公司市值，B 是公司净资产（资产-负债）具体可以在上市公司的年报中找到，相比于市盈率，市净率更稳定一些，因为盈利是一个短时指标，而净资产则是一个累计指标。</p>
<p>当一家公司还没产生亏损，大多数时候净资产都是增长的时候，市净率就可以作为一个比较好的参考（亏损也可以作为负面的参考要素）</p>
<p>市净率主要有以下的几个方面影响：</p>
<p><strong>净资产收益率 ROE</strong>：每单位资产的变现能力，企业对资产的利用率，螺丝钉和查理芒格都认为其是一个较为关键的指标，该指标与股票的长期收益率十分相关，相当于他们对我们贡献的这一笔股票投资的变相能力，所以长期下来会和股票的收益十分类似。</p>
<div>
$$ 
ROE = 净利润/净资产
 $$
</div>
<p>市净率的有效范围：</p>
<ul>
<li>① 资产的稳定性，有的资产能够随着时间增值，例如酒，有的则会随着时间贬值（周期性产品没有及时销售），<strong>资产的稳定性越高，市净率的有效性更高。</strong></li>
<li>② <strong>不适用于无形资产</strong>：如果企业的收益主要来源是其中的人才，专利，影响力，话语权，那么市净率的参考价值就比较低（例如律师或者 openai）</li>
<li>③ 整个行业大规模亏损的情况下不适合参考市净率；</li>
<li>④ 短期经济危机，盈利短期不稳定，可以参考市净率作为辅助判断</li>
</ul>
<h4 id="股息率衡量现金分红收益率">股息率：衡量现金分红收益率</h4>
<p>股息率和分红率要记得区分，定义上有一些类似，但是含义和功能就完全不一样了：</p>
<ul>
<li>股息率： $现金分红/公司市值$ ，股价越低，股息率越高，相同分红的情况下</li>
<li>分红率： $现金分红/总净利率$ ，通常是一个事先定义的值，大多数情况下不会改变</li>
</ul>
<p>股息率的作用是能<strong>将公司的净利润增长映射到股价</strong>上（投资者的现金收益），同时<strong>股息是无需我们出售股权的时候也能获取到的现金流</strong>，这也是国家分享国有企业收益的方式，通过持有高股息的股票资产组合，就可以在无需关注股价涨跌的情况下，获取越来越高的现金分红。</p>
<p>分红和盈利挂钩却不与股价挂钩，所以一般企业不出现大问题的情况下，分红都会逐年上涨，（偶尔盈利下降也会下降），因为上述特点，针对<strong>高股息的品种进行投资也是一种投资方式</strong>，这也是很多人选择投资的方式：<strong>选择分红高、估值偏低的股票</strong>。</p>
<p>这里贴两个使用高股息率投资组合的典型案例：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240317115709.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240317115709.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240317115709.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="如何利用估值去做投资">如何利用估值去做投资</h3>
<blockquote>
<p>按照盈利的趋势的分类去分析基金，主要可以分为 5 个品种：盈利保持不变、盈利长期稳定增长、盈利快速增长、盈利大起大落、盈利衰退。</p>
</blockquote>
<p>其中大起大落和衰退的品种投资难度太高，<strong>不适合</strong>普通投资者的<strong>投资主力</strong>，所以主要对前三种进行分析。</p>
<h4 id="盈利保持不变看现金流收益率高低">盈利保持不变：看现金流收益率高低</h4>
<p>实际上就是一个债权类的资产，就和国债一样确定的稳定收益，对这类品种的估值，主要看现金收益率的高低，如果现金流收益率满意就可以考虑，但是要考虑这类品种的安全性，不能中途倒闭或暴雷。</p>
<p>投资这类产品中有以下的Tips：</p>
<ul>
<li>这类品种的话可以参考债券类的收益，如果收益和债权类相似接近，是正常的，如果稳定的收益远高于债券基金的平均收益，背后可能有坑或者风险。</li>
<li>这类品种的现金流收益率必须要高于国债的收益率，因为国债安全性最高，股票类的安全性没有那么高，因此如果现金流收益率没有更高的话，就没有考虑的必要。</li>
</ul>
<div>
$$ 
现金流收益率=现金流/市值
 $$
</div>
<p>牛市中很多品种的市值大涨，导致其实际的收益很低，如果投资者看重这种中短期的赚钱效应去哄抢，导致异常上涨，这是非常不明智的。</p>
<h4 id="盈利稳定增长盈利收益率法">❓盈利稳定增长：盈利收益率法</h4>
<div>
$$ 
盈利收益率=公司盈利/公司市值
 $$
</div>
<p>可以发现其为市盈率的倒数，其是一种绝对估值法，通常使用这种估值进行投资的时候遵循以下三个原则：</p>
<ol>
<li>当指数基金的盈利收益率&gt;10%且&gt;国债收益率两倍以上的时候投资</li>
<li>当盈利收益率小于债券基金预期收益率(19 年的时候为 6.4%)的时候卖出</li>
</ol>
<blockquote>
<p>怎么去计算和看到一个基金的这些数据，这是后面急需解决的问题。</p>
</blockquote>
<p>借由盈利收益率，我们说明以下绝对估值法：其将一个品种未来的现金流<strong>折现</strong>到当前，计算当前的理论值，如果当前股价低于该现值，说明当前股价被低估了，如果低估了很多，就可以考虑投资。</p>
<p>这里的折现可以简单理解为：按照一个百分比，将未来的现金折算到当前为多少钱，例如 2 年后的 100 元，按照折现率 10%,到现在就相当于为 $100/(1.1)^2=86.2$ ，即当前的估值就是 86.2，这里的折现率就是我们想要的<strong>年复合收益率</strong> 。</p>
<p>但是收益当然是越高越好，大家期望的收益都不同，那么用于估计价值的时候，往往会使用国家的社会平均折现率，（前两年我国公布的为 8%），当然为了规避风险，股票计算的时候往往会使用更大的数字，10%~12%去计算。市盈率的第一条法则实际上就是该估值法的简单应用。</p>
<div>
$$ 
永续年金的现金流的现值=每年的现金流/折现率
 $$
</div>
<div>
$$ 
市值 = 盈利/盈利收益率
 $$
</div>
<p>所以只有当盈利收益率&gt;折现率的时候，市值现金流才会实现正向的增长，因此才有投资的价值，否则实际上该企业的发展并赶不上时代的变化。</p>
<p>上述这种计算方法，是适合未来现金流固定不变的品种，但是实际上投资的指数基金的盈利会稳定增长，因此应该使用<strong>永续增长年金模型</strong></p>
<div>
$$ 
永续增长型年金的现金流现值（市值） = 每年现金流（盈利）/ （折现率（盈利收益率）- 增长率）
 $$
</div>
<p>例如一个公司一年赚 100w，按 10%算折现率，5%算增长率，则算出来其市值估值分别为 1000w 和 2000w。</p>
<p>而格雷厄姆考虑到安全边际效应，不使用增长型模型，因为就算增长率保持在 10%不再继续上涨，也是一个可观的投资。</p>
<p>盈利收益率法的原理。它本质上是一个折现率为 10%的绝对估值法，在这种情况下的<strong>定投策略</strong>如下：</p>
<ul>
<li>当盈利收益率大于10%时，分批投资（即继续定投）</li>
<li>盈利收益率小于10%，但大于6.4%时，坚定持有已经买入的基金份额。</li>
<li>当盈利收益率小于6.4%时，卖出基金。</li>
</ul>
<p>🔥<strong>局限性</strong>：只适合于流通性比较好、盈利比较稳定的品种。如果是盈利增长速度较快或者盈利波动比较大的指数基金，则不适合使用盈利收益率法</p>



  
  

<blockquote class="alert-blockquote alert-quota">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Quota</span>
  </p>
  <p>目前国内适合盈利收益率法的品种，主要是上证红利、中证红利、上证 50、基本面 50、上证 50AH 优选、央视 50、恒生、恒生中国企业等指数的指数基金。这几个品种的投资很简单，当盈利收益率大于 10%时就可以投资，小于 6.4%时就可以卖出。</p>

</blockquote>
<h4 id="盈利快速增长博格公式法">盈利快速增长：博格公式法</h4>
<p>如果一个品种长期盈利的增长速度远远高于 10%，那么不适合用盈利收益率法，而因该用博格公式法；其主要针对的是<strong>盈利高速增长的品种</strong>和<strong>盈利呈周期性变化的品种</strong>。</p>
<div>
$$ 
指数基金净值=市盈率*盈利+分红
 $$
</div>
<p>也就是说影响我们股民收益的一个是股息率决定了分红收成，另一个是市盈率，决定了一个公司将盈利转化为市值的能力，股息通常而言是确定的，一般而言，当价格被低估的时候，股息率就更高，最需要考虑的其实是市盈率的变化和未来盈利的增长。</p>
<p>复习一下市盈率： $市盈率=公司市值/公司盈利$ 市值由股价计算而来。</p>
<p>对于一个宽基指数来说，<strong>市盈率通常是在一个范围内来回波动</strong>，不会太高也不会太低，例如沪深，历史上最低是 8，最高时 48，熊市中在 8<del>11，牛市中在 17</del>48，其他时候都在 8~17 来回波动，那么也就是说当我们<strong>买入的如果市盈率低</strong>的话，那么我们就可以从中获取显著的收益，如果在高点买入，那只能看下跌的空间了。</p>
<p>需要注意：短期内，指数基金的涨跌，主要是由估值的变化决定的。但是时间拉长后，指数基金的上涨，是由背后公司的盈利增长和分红积累推动的。这个因果关系要搞清楚。</p>
<p>👍因此如果给估值和盈利增长排优先级的话：盈利增长良好为先，第二个是在估值处于低位的时候买入；因此改良后的定投方法为：</p>
<ul>
<li>挑选长期盈利增长率良好的品种</li>
<li>在估值处于低位的时候买入：一个是自身历史估值处于低位，另一个是估值要和自身的盈利增长速度匹配。</li>
<li>高估时候卖出</li>
</ul>
<blockquote>
<p>估值和增长速度匹配的意思是什么呢？
比如说美国股票市场的指数，长期盈利增长率大约是 10%，美国股市过去百年的市盈率平均值，大约是 15 倍。这就是一个对应关系。</p>
</blockquote>
<p>只有匹配正常的，能避免一些炒作的股票，提高一些置信度。</p>
<p>从全世界范围来看，成熟国家的股票市场，长期盈利增长率在8%~10%，市盈率平均值在 15 倍左右。这是一个可以参考的估值区间。如果盈利增长率更高，那可以享受的市盈率平均值也会更高。但是很少有品种能长期保持 30%以上的盈利增长速度，所以对市盈率数值超过30 倍的指数基金，一定要慎之又慎。</p>
<p>计算是否匹配的时候也可以使用 PEG 指标</p>
<div>
$$ 
PEG=市盈率数值/长期盈利增长速度数值
 $$
</div>
<p>PEG 的正常范围在 1~2 之间，&lt;1 的话还是比较好的，可能是一种被低估了的情况，&gt;2 的话就要小心了，宁可不投资都。</p>
<p>结合上述的所有，博格公式法总结如下：</p>
<ul>
<li>长期盈利增长速度大幅高于 10%的品种，适合使用博格公式法。</li>
<li>使用 PEG 规避风险, 避免投资市盈率长期保持很高数值的产品</li>
<li>考虑市盈率的历史数据，如果市盈率处于历史低位，那么大概率该产品被低估，可以考虑买入</li>
<li>如果市盈率处于高位，或者 PEG&gt;2 那么大概率被高估，需要慎重。</li>
<li>（补充）低估买入，高估卖出</li>
</ul>
<p>数据的查找和计算并不方便，而且也没有准确的估值，螺丝钉自己会公布一些，可以去看。</p>
<h2 id="定投的具体操作方式选择">🧰定投的具体操作方式选择</h2>



  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>上述的文章讲的是，买什么（长期收益优秀的策略加权指数基金），什么时候买（低估时），现在还有一个问题就是什么时候买。</p>

</blockquote>
<p>主要是以下的几种：<strong>定期定额</strong>、<strong>定期不定额</strong>、<strong>慧定投</strong>（基于均线的定期不定额）、<strong>价值平均策略</strong>（基于市值的定期不定额）、<strong>估值定投策略</strong>（基于估值的定期不定额），这些策略的大概意思从名字也能看出来，这里就不作太基本的介绍。</p>
<p>首先是<strong>定期定额</strong>基本但有缺陷，一般不推荐：A 股中不推荐：收入增长速度变化、通货膨胀变化、钝化、以及不够灵活。通常会采取定期不定额的方法。</p>
<p><strong>定期不定额</strong>：除了收入的变化，指数基金本身的涨跌，也会导致当前定投周期，投资价值的变化，如果我们在低估周期定投，且短期内指数基金下跌了，实际上他的投资价值反而提高了，实际上我们的策略应该是，在指数基金处于低估区域的时候去投资，而由于其本身的波动大，区间内可能会出现低估和高估的情况，我们应该再低估的时候买入更多，拉低整体均价，在高估的时候不投乃至卖出。</p>
<p>这种策略也叫“定投收益放大器”，有种越跌越买的感觉，在这个基础上，因为指数基金上涨是长期的，下跌时短期的，这样，如果我们在短期下跌的时候拉低均价，我们的收益会进一步增加。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240317190704.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240317190704.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240317190704.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><strong>慧定投</strong>：参考均线来做的定期不定额，均线（过去一段时间的平均价格），支付宝通常是 500 日均线，如果高于均线就少投一些，随着幅度越大投的越少。如果低于过去 500 个交易日的均线就多投一些，少得越多，投的越多。这个可以查看支付宝中的说明。</p>
<p>慧定投的缺陷：①支付宝这边并非参考的单个产品对应指数的均线，其只有个别几种产品指数的均线；②无法帮助区分基金，任何基金都可以使用该慧定投策略。</p>
<p><strong>价值平均策略</strong>：又称为市值恒定策略，给手里的指数基金设定一个市值增长速度，比如说，计划每个月投 1k，到第二个月的时候，由于基金的波动，原本的 1k 可能不止 1k 或者少于 1k 了，无论是多了还是少了，我们就将其补充到 2k，这也是一种方式。思想上也是一样的，这个增长速度可以是绝对值也可以是比例。</p>
<p>价值平均的缺陷：在波动比较大的股市，可能遇到大跌的时候慧需要拿出较多金额进行补仓，但是我们也可以手动为其设定每个月的上线。</p>
<p><strong>估值定投策略</strong>：上面两种投资方式都是简单有效的，但是他们都没有考虑指数基金本身的投资价值，上述对基金的选择中，我们提到了在基金被低估的时候进行投资，才能取得最好的长期收益。因此我们结合两件事：</p>
<ul>
<li>在<strong>熊市</strong>，指数基金被<strong>低估</strong>的时候开始投资</li>
<li>配合估值，在估值较低的时候买入更多。</li>
</ul>
<p>🌟具体而言，每个月定投的金额计算公式如下,公式中的 n 就是<strong>定投放大器</strong>，n 越大，放大的收益越大，但是相应的可能需要的金额也会更多。</p>
<div>
$$ 
每月定投的金额=首次低估时的定投资金*(\frac{当月的盈利收益}{首次的盈利收益率})^n
 $$
</div>
<blockquote>
<p>按照螺丝钉的经验，假如说初始定投金额是 1000 元，n 设置为 2，当遇到 A 股极端下跌，指数基金到了历史最低估值的阶段，定投金额可能就会变成 2400 元<del>2600 元。大多数时间里，定投金额会在 1000 元</del>1500 元。这是一个大致的参考区间。</p>
</blockquote>
<p>估值定投的缺点：① 只适合指数基金，不适合主动基金，要存在事先确定/公开透明的股票，比例，才能进行后续的计算和估值。② 估值有时候不太稳定，可能会由于盈利下滑等原因导致失效，例如金融危机的时候。市盈率也应该降低，但是标普 500 指数因为背后公司盈利下滑，导致市盈率反而被动提升到了八九十倍（市盈率=市值/盈利）</p>
<blockquote>
<p>金融危机的 case 在做量化的时候，时很典型的反例，需要结合起来考虑怎么优化。</p>
</blockquote>
<p>如果估值失效的时候：</p>
<ul>
<li>沿用盈利大幅下滑之前的盈利数据，或者多年平均盈利数据。</li>
<li>用其他的估值指标：例如净资产。</li>
</ul>
<h2 id="止盈策略什么时候卖出">😀止盈策略：什么时候卖出</h2>
<p>常见的止盈策略有三种，三种方式都有道理，但是适用的范围有区别。</p>
<ol>
<li>从自身收益角度考虑止盈</li>
<li>从投资品种的价值角度考虑止盈</li>
<li>不止盈，在低估的时候买入，长期持有，依靠基金的分红来获得现金流</li>
</ol>
<h4 id="自身收益止盈">自身收益止盈</h4>
<p>第一种就是最简单的，当我们账面收益达到了我们设定的收益率的时候，我们就直接赎回，不管后续的发展了，这种方法需要注意的就两点：</p>
<ol>
<li>不能太频繁止盈</li>
<li>止盈率的设定非常重要，通常设置为 30%，和<strong>可转债</strong>相关，可以去补充了解以下相关的知识。</li>
</ol>
<p>其有以下缺点/特点：</p>
<ol>
<li>投资开始阶段不同，会出现有人出场有人入场</li>
<li>牛市的疯狂涨幅会更高，投资者会损失部分利益</li>
<li>适合波动大的品种，因为赚 30%就直接止盈，按照定投低估指数基金，30%收益率就止盈，在 2~3 年内实现止盈获利是大概率的。</li>
</ol>
<h4 id="按照估值止盈">按照估值止盈</h4>
<p>就是前文中反复提及的，<strong>在价格大幅低于其估值的时候买入，在价格大幅高于其估值的时候卖出</strong>，这种方式的投资周期通常会比 30% 止盈的方式的周期更长，因为一般得到大牛市的中后期，才会到高估区域，如果使用这种止盈方式的话需要耐心持有。</p>
<p>其优点：</p>
<ol>
<li>在牛市收益高，通常从低估到正常估值，从正常估值到高估，每个区域都会有 30%~40% 的涨幅。</li>
<li>投资者可以比较长的享受到投资品种本身盈利上涨带来的收益，由于盈利始终上涨，市值也会稳步增长。</li>
</ol>
<p>缺点：</p>
<ol>
<li>需要耐心</li>
<li>对策略指数基金的品种有要求，需要快速增长盈利：一般是优秀的策略加权宽基基金，或者优秀的行业基金指数</li>
</ol>
<p>通过估值进行止盈的策略可以按照定期不定额的策略进行卖出，结合起来就是：</p>



  
  

<blockquote class="alert-blockquote alert-important">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0 1 14.25 13H8.06l-2.573 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25Zm7 2.25v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 9a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path>
    </svg>
    <span>Important</span>
  </p>
  <p>指数基金被低估的越多，我们买入越多；当指数基金进入高估区域，我们把手里的基金分成多份，估值高出越多，我们卖出的比例越高，进行分批止盈，也叫做梯度止盈。</p>

</blockquote>
<p>这种方式可以避免我们在牛市的时候完全错过后面的收益，不过风险就是可能牛市结束还没卖完，算是一个权衡，避免过多损失和过多亏损。</p>
<p>具体操作示例：例如在 20 倍市盈率的时候进入了高估区域，我们有 1w 份基金，我们卖出 10%,当达到 24 倍市盈率的时候卖出：</p>
<div>
$$ 
10\%* (24/20) ^n  
 $$
</div>
<p>这里的 20 是假设，10% 可以自由调整</p>
<h4 id="不止盈">不止盈</h4>
<p>不止盈，在明显低估的时候买入，长期持有，依靠分红来获取日常消费的现金流，如果日常收入需求完全可以靠股息分红来支撑，那么这个就是最好的投资策略了。</p>
<p>为什么可以长期持有？因为<strong>指数基金本身的迭代特性</strong>只要其背后的公司正常运营，其盈利是长期上涨的，现金分红作为盈利的一部分也会长期上涨，因此将指数基金转换为一个利息收益不断上涨的超长期理财产品。</p>
<p>但是这种策略有以下的条件：</p>
<ul>
<li>需要选择股息率较高，分红较多的指数基金</li>
<li>长期分红的收益和初始买入的股息率关系很大</li>
</ul>
<p>一定要在初期股息率很高的时候投资，一般 4%以上是还不错，5%以上是少见的好机会，2%都不到的话就要很小心。</p>
<blockquote>
<p>通常股息率比较高的时候，往往也是大熊市指数基金处于低估的时候，也暗含了低估值投资的理念。所以如果打算长期持有获取分红收益，一定要在股息率比较高的时候再买入.</p>
</blockquote>
<p>A 股中较为适合的主要是大盘宽基指数基金：如上证 50、沪深 300、恒生、H 股、中证红利、红利机会等。</p>
<h4 id="止盈策略选择">止盈策略选择</h4>
<p>第一种止盈：适合波动很大，暴涨暴跌的产品，分红不多，周期性很强，这种止盈策略效率更高。</p>
<p>第二种止盈：按照估值止盈，通常是 7~10 年止盈一次，这种方式适用于长期稳定的指数基金，最终收益是叠加多个牛市的收益，如果能在熊市入场，收益会更好。</p>
<p>第三种止盈：适用于红利、股息率高，且长期经营和收益状况都比较稳定的指数基金。</p>
<p>通常如果不急着用钱可以考虑使用第二种止盈方式，一般会在牛市的中后期才进行止盈，一般 7<del>10 年一次。否则可以按照 30%的方式，一般 2</del>3 年就会有卖出的机会。</p>
<h2 id="制定完整的定投计划">制定完整的定投计划</h2>
<ul>
<li>根据收入和开支，指定合理的定投额度: 通常 3 年为期，牛市缩短，(收入-开支)/2</li>
<li>筛选投资的品种: 被低估的指数基金；</li>
<li>设定好买卖区间：软件上设置定投计划；</li>
<li>定期根据行情进行优化，定时不定额的买入&amp;卖出；</li>
</ul>
<h3 id="养老投资计划">养老投资计划</h3>
<p>稳健为主，以 100-年龄的方式来决定配置指数基金的比例，例如 70 岁，使用 30%的现金来配置指数基金，然后将该部分基金分成 20 份，按月分配，建议是红利类；其他的以银行理财产品、货币这种稳健的方式为主。</p>
<p>👍可以参考 CPPI 策略来指定保本投资组合：</p>
<blockquote>
<p>即大部分资金配置货币基金、理财产品、债券，少部分资金配置低估指数基金。比如说 100 万元，用 90 万元配置年收益率为 5%的理财产品，剩下的 10 万元配置低估指数基金。一年后，如果股市下跌，低估指数基金跌幅最高为 20%左右，那 10 万元还剩下 8 万元，但是理财产品可以获得 4.5 万元的收益，合计就是 90+4.5+8=102.5 万元，还是保本的。</p>
</blockquote>
<h3 id="教育定投">教育定投</h3>
<p>特点在于，要用钱的时间是固定的，这种香港有很多类似的投资组合，可以参考我妹的那种，距离用钱的时间越远，选择低估指数约值得考虑，卖出点可以放高，时间越近，越要考虑稳妥。</p>
<h2 id="常见问题">常见问题</h2>
<h3 id="基金净值的高低对收益有影响吗">基金净值的高低，对收益有影响吗？</h3>
<div>
$$ 
基金净值=基金规模/基金总份额数量
 $$
</div>
<p>答：无，追踪同一个指数的基金，净值高低对投资收益影响不大。</p>
<h3 id="abc-类的区别">ABC 类的区别</h3>
<p>ABC 指的是收费的方式：</p>
<ul>
<li>A：前端收费，收取申购和赎回费，现在第三方平台打折，申购几乎免除，因此 AB 同质化，且有时候赎回费率更低。</li>
<li>B：后端收费，收取赎回费，免除申购费</li>
<li>C：不收取申购赎回费，收取服务费。</li>
</ul>
<p>C 类通常是给短期投资者提供的，长期起来 A 类反而更有优势，因为服务费较高； &amp;&amp; 一般 7 天之内赎回会有惩罚性费率 1.5%，一般长期 A(B)，短期 C。</p>
<h3 id="场内基金和场外基金哪个更划算">场内基金和场外基金哪个更划算</h3>
<p>场内（证券交易所内）一般是散户之间交易，人心更加勾心斗角，这里暂不介绍，主要在互联网上用场外交易即可（和官方申购赎回），如果有的已经封盘了，倒是可以在开通股票账户后，去对应的证券交易软件上，购买那些已经封闭的。</p>
<p>场内的优势在于交易更加实时一些，后续也可以利用这个来操作</p>
<h3 id="已经有一笔资金要分批投入吗">🔥已经有一笔资金，要分批投入吗</h3>
<p>这实际上是和自己的预测相关的，如果你认为不会再低了，就一次性投入，如果你想分批，说明你认为现在不是最低点，或者略高。</p>
<p>如果判断对了当然好，如果错了就可能会亏损，因此建议使用分批来排除自己的主观臆断，减少损失的风险，所以推荐还是<strong>越跌越买</strong>：</p>
<blockquote>
<p>通常是把资金分成 20 份，进入低估区域后，投入 1 份，也就是 5%。这里的 5%，有点类似前面介绍定期不定额定投时的初始定投金额，之后每个月投入一份，如果市场下跌了，可以提高投入的比例和金额。用这种方式，可以在 10~20 个月里，把一笔资金分批配置成低估指数基金</p>
</blockquote>
<p>20 个月是一个经验数字，一般低估区域的平均时间长度为 1~2 年，最长也不过三年，因此方便在熊市建仓。</p>
<h3 id="日定投周定投还是月定投">日定投、周定投、还是月定投</h3>
<p>日定投的周期太短了，首先排除日投的策略，一般都是周或者月（每个月的金额差不多），当周期拉长以后，实际上实际收益差距不大，主要看自己是否看到下跌以后会忍不住，如果会的话就直接周投，不然就月投更省心。</p>
<h3 id="定投一定能降低成本吗">定投一定能降低成本吗</h3>
<p>钝化效应：当定投的资金在持有的资金的 5% 以下后，增加的资金占比太小了，因此对原有资金的影响不大，这就是钝化效应，这个时候想要在下跌的时候降低成本就不行了。所以还是要定期不定额，下跌的时候多买点，才能更有效的降低成本。</p>
<p>此外当进入高估区域的时候，我们进行分批卖出的操作，然后等下跌再分批投入被低估的指数基金，这样流动性就起来了，也会减少钝化效应的情况。</p>
<h3 id="定投多久才能开始盈利指数">定投多久才能开始盈利（指数）</h3>
<p>1~3 年，通常 1 年多，耐心是最好的品德</p>
<h3 id="看点数来买基金靠谱吗">看点数来买基金靠谱吗？</h3>
<ul>
<li>短期来看可能会有一定的效果，长期迟早会失效。</li>
<li>点数本质上是从指数开始计算的 100 开始增长的，因为市盈率的变化，和市场一直在发展（盈利一直在增长，故而市值会增长，点数也就一直增长）</li>
<li>所以点数其实是一个短期波动长期上升的模型（同行业、国家的运势和发展）</li>
</ul>
<h3 id="是否有完美的高抛低吸的投资方法">是否有完美的高抛低吸的投资方法</h3>
<p>无，但是长期走势是有迹可循的，原因是股市的复利效应，股票资产是有复利的，公司会把盈利的一部分再投入生产来产生更多的盈利&amp;分红发放，都会推动股市上涨。</p>
<p>估值低不代表短期会上涨，但是估值低在 3~5 年的收益就会越高，</p>
<h3 id="定投低估的指数基金最大的浮亏是多少">定投低估的指数基金，最大的浮亏是多少</h3>
<p>我们以 2018 年的熊市为例。2018 年，是 A 股历史上的第二大熊市，沪深 300 指数跌幅大约为25%，代表了主流指数的平均跌幅。不过虽然指数下跌 25%，但如果定投的话，在微笑曲线的作用下，浮亏会大大减少。通常只有 1/3~1/2 的浮亏，也就是浮亏在 10%~15%。</p>
<p>上述是宽基在大熊市的浮亏情况，使用合适的定投方法，浮亏也会更小。</p>
]]></content:encoded>
    </item>
    <item>
      <title>LearnWeb15-Web实战01-首页设计</title>
      <link>https://aikenh.cn/posts/learnweb16-web%E5%AE%9E%E6%88%9801-%E9%A6%96%E9%A1%B5%E8%AE%BE%E8%AE%A1/</link>
      <pubDate>Sat, 17 Feb 2024 08:28:28 +0000</pubDate>
      <guid>https://aikenh.cn/posts/learnweb16-web%E5%AE%9E%E6%88%9801-%E9%A6%96%E9%A1%B5%E8%AE%BE%E8%AE%A1/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-summary&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Summary&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;设计个人首页作为 HTML 和 CSS 的实战，主要设计以下的几个部分，导航栏，侧边栏，logo，页脚，背景，以及一个简单的个人介绍页面，首先不考虑使用框架和库，仅对整体流程做熟悉，使用纯 HTML 和 CSS 进行基础实现。后续考虑使用框架和组件库进行重写。&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>设计个人首页作为 HTML 和 CSS 的实战，主要设计以下的几个部分，导航栏，侧边栏，logo，页脚，背景，以及一个简单的个人介绍页面，首先不考虑使用框架和库，仅对整体流程做熟悉，使用纯 HTML 和 CSS 进行基础实现。后续考虑使用框架和组件库进行重写。</p>

</blockquote>
<p><a href="https://www.checklist.design/" target="_blank" rel="noopener">CheckList for Web Design</a>
 : Using this website to checkout those element u missed in your design. Prepare for those elements. Get Ready and Start.</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240219134111.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240219134111.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240219134111.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="nav-bar-页眉的导航栏设计">Nav-Bar 页眉的导航栏设计</h2>
<h3 id="buger-下拉菜单侧边菜单">Buger 下拉菜单(侧边菜单)</h3>
<p><a href="https://alvarotrigo.com/blog/hamburger-menu-css/" target="_blank" rel="noopener">https://alvarotrigo.com/blog/hamburger-menu-css/</a>
</p>
<h3 id="flex-布局设计">flex 布局设计</h3>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240221035525.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240221035525.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240221035525.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>使用 html css 进行布局时，如果计划使用 flex 等布局，避免无谓的划分子集的 div 等 box，避免多余的额外对齐工作，原型和草稿确认布局是很重要的。例如上述的导航栏，分成左右两个 div 即可，如果将搜索框等独立出来，在后续对齐和确认间距的时候会多出很多麻烦。</p>
<blockquote>
<p>可以缩减为仅使用一个 div，使用 flex 的布局技巧来使得元素一半左对齐一半右对齐即可，下面时具体说明。可以参考文献 1 的《使用自动的外边距在主轴上对齐》章节。</p>
</blockquote>
<p>如果希望让 flex 子元素靠右显示，可以在子元素中定义 <code>margin-left: auto;</code> (auto 也可使用其他数值单位替代)，参考 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_flexible_box_layout/Aligning_items_in_a_flex_container" target="_blank" rel="noopener">👍MDN弹性盒子容器中的对齐方式</a>
 |  <a href="http://m.tnblog.net/notebook/article/details/7906" target="_blank" rel="noopener">flex子元素靠右</a>
 | <a href="https://blog.51cto.com/mouday/4373479" target="_blank" rel="noopener">Flex的最后一个元素靠右</a>
 | <a href="https://developer.mozilla.org/zh-CN/docs/Glossary/Flexbox" target="_blank" rel="noopener">Flexbox</a>
</p>
<ul>
<li>align-items 如果没有设置正确的话，所有的元素会按照撑满 flex 容器的高度去对齐。</li>
<li>使用 margin:auto 可以实现元素的居中</li>
<li>使用 align-self 可以实现单个 flex 子项的不同对齐方式。</li>
</ul>
<p>可能接着阅读更多布局相关的资料，加深对布局的认识，以及正确选择合适的布局：<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Layout_cookbook" target="_blank" rel="noopener">Mdn Layout Cookbook</a>
</p>
<h3 id="search-bar-搜索框">Search Bar 搜索框</h3>
<p>搜索框设计：使用 logo 和 input 的形式来实现一个搜索框的样式，如下图所示，由三个 box 的组合而成：form 包裹内部的 svg 和 input 两个 box。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240221034829.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240221034829.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240221034829.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>

具体的 HTML 如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">form</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;search-tool&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">svg</span> <span class="na">xmlns</span><span class="o">=</span><span class="s">&#34;http://www.w3.org/2000/svg&#34;</span> <span class="na">width</span><span class="o">=</span><span class="s">&#34;17&#34;</span> <span class="na">height</span><span class="o">=</span><span class="s">&#34;17&#34;</span> <span class="na">viewBox</span><span class="o">=</span><span class="s">&#34;0 0 17 17&#34;</span> <span class="na">fill</span><span class="o">=</span><span class="s">&#34;none&#34;</span>
</span></span><span class="line"><span class="cl">		<span class="na">role</span><span class="o">=</span><span class="s">&#34;img&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;icon nav-v2-search__icon&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">		<span class="p">&lt;</span><span class="nt">path</span>
</span></span><span class="line"><span class="cl">			<span class="na">d</span><span class="o">=</span><span class="s">&#34;M1.5 7.75C1.5 9.4076 2.15848 10.9973 3.33058 12.1694C4.50269 13.3415 6.0924 14 7.75 14C9.4076 14 10.9973 13.3415 12.1694 12.1694C13.3415 10.9973 14 9.4076 14 7.75C14 6.0924 13.3415 4.50269 12.1694 3.33058C10.9973 2.15848 9.4076 1.5 7.75 1.5C6.0924 1.5 4.50269 2.15848 3.33058 3.33058C2.15848 4.50269 1.5 6.0924 1.5 7.75V7.75Z&#34;</span>
</span></span><span class="line"><span class="cl">			<span class="na">stroke</span><span class="o">=</span><span class="s">&#34;currentColor&#34;</span> <span class="na">stroke-width</span><span class="o">=</span><span class="s">&#34;1.5&#34;</span> <span class="na">stroke-linecap</span><span class="o">=</span><span class="s">&#34;round&#34;</span> <span class="na">stroke-linejoin</span><span class="o">=</span><span class="s">&#34;round&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">		<span class="p">&lt;/</span><span class="nt">path</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">		<span class="p">&lt;</span><span class="nt">path</span> <span class="na">d</span><span class="o">=</span><span class="s">&#34;M12.814 12.8132L15.5 15.4999&#34;</span> <span class="na">stroke</span><span class="o">=</span><span class="s">&#34;currentColor&#34;</span> <span class="na">stroke-width</span><span class="o">=</span><span class="s">&#34;1.5&#34;</span>
</span></span><span class="line"><span class="cl">			<span class="na">stroke-linecap</span><span class="o">=</span><span class="s">&#34;round&#34;</span> <span class="na">stroke-linejoin</span><span class="o">=</span><span class="s">&#34;round&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">path</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;/</span><span class="nt">svg</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">placeholder</span><span class="o">=</span><span class="s">&#34;Search...&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;&#34;</span> <span class="na">autocapitalize</span><span class="o">=</span><span class="s">&#34;off&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;search-form&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>为了美观我们去除 input 原本的边框和底色，同时避免内容溢出，css 可参考如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">nav-func</span> <span class="p">.</span><span class="nc">search-tool</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">margin-top</span><span class="p">:</span> <span class="mi">5</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">background-color</span><span class="p">:</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">14</span><span class="p">,</span> <span class="mi">82</span><span class="p">,</span> <span class="mi">30</span><span class="p">,</span> <span class="mf">0.28</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">border-radius</span><span class="p">:</span> <span class="mi">5000</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">max-width</span><span class="p">:</span> <span class="mi">180</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">nav-func</span> <span class="p">.</span><span class="nc">nav-v2-search__icon</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">padding-left</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="c">/* position: relative; */</span>
</span></span><span class="line"><span class="cl">    <span class="k">display</span><span class="p">:</span> <span class="kc">inline-block</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="c">/* left: 15px; */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">nav-func</span> <span class="p">.</span><span class="nc">search-tool</span> <span class="nt">input</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">background</span><span class="p">:</span> <span class="kc">transparent</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">color</span><span class="p">:</span> <span class="kc">black</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">border</span><span class="p">:</span> <span class="kc">none</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">outline</span><span class="p">:</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">overflow</span><span class="p">:</span> <span class="kc">hidden</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>最好结合其父元素来限制搜索框的最大最小 width 以及 logo 的位置，同时为了小窗口的响应式设计可以结合媒体查询来控制搜索框的显示与否。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">@</span><span class="k">media</span> <span class="nt">screen</span> <span class="nt">and</span> <span class="o">(</span><span class="nt">max-width</span><span class="o">:</span> <span class="nt">850px</span><span class="o">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="nc">nav-func</span> <span class="p">.</span><span class="nc">search-tool</span> <span class="nt">input</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="k">visibility</span><span class="p">:</span> <span class="kc">hidden</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="k">display</span><span class="p">:</span> <span class="kc">none</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="k">width</span><span class="p">:</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这里介绍一下 <code>display: none;</code> 和 <code>visibility: hidden;</code> 的区别：</p>
<ul>
<li>如果使用 <code>visibility: hidden;</code> 那么其结构，如在 flex 中的占位会仍然存在，只是元素并不显示，有时候我们需要使用它</li>
<li>如果使用 <code>display: none;</code> 那么其内容和结构都会完全小时，我们在计算的时候就仿佛 html 中没有这个元素一般，在一些响应式的场景会需要用到</li>
</ul>
<h3 id="switch-主题切换按钮亮暗色主题切换">Switch 主题切换按钮/亮暗色主题切换</h3>
<p>给 body 添加 darktheme class 属性来为页面的基本元素设置亮暗的双主题切换，使用一下的选择器前缀来为不同主题下的页面添加不同背景颜色的属性：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">body</span><span class="p">.</span><span class="nc">dark-mode</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-color</span><span class="p">:</span> <span class="mh">#232946</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="c">/* background: url(../images/background-dark.jpeg); */</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-size</span><span class="p">:</span> <span class="kc">cover</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-repeat</span><span class="p">:</span> <span class="kc">no-repeat</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-attachment</span><span class="p">:</span> <span class="kc">fixed</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>建议使用预先定义好的不同主题的色彩变量来实现无需多重定义各个单元的元素：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">:</span><span class="nd">root</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--clr</span><span class="p">:</span> <span class="mh">#141e15</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--bga</span><span class="p">:</span> <span class="mh">#004643</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--btm-color</span><span class="p">:</span> <span class="mh">#f9bc60</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--para-color</span><span class="p">:</span> <span class="mh">#abd1c6</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--font-color</span><span class="p">:</span> <span class="mh">#fffffe</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nv">--stroct-color</span><span class="p">:</span> <span class="mh">#001e1d</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>按照自己想要的设计亮暗切换按钮：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;theme-toggle&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">button</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;sun&#34;</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">ion-icon</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;sunny-outline&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">ion-icon</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">button</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;moon&#34;</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">ion-icon</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;moon&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">ion-icon</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="c">/* theme switcher here */</span>
</span></span><span class="line"><span class="cl"><span class="nt">header</span> <span class="p">.</span><span class="nc">theme-toggle</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">position</span><span class="p">:</span> <span class="kc">absolute</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">top</span><span class="p">:</span> <span class="mi">20</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">right</span><span class="p">:</span> <span class="mi">20</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">z-index</span><span class="p">:</span> <span class="mi">2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">header</span> <span class="p">.</span><span class="nc">theme-toggle</span> <span class="nt">button</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">background</span><span class="p">:</span> <span class="kc">transparent</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">border</span><span class="p">:</span> <span class="kc">none</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-size</span><span class="p">:</span> <span class="mf">1.5</span><span class="kt">em</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">header</span> <span class="p">.</span><span class="nc">theme-toggle</span> <span class="p">.</span><span class="nc">sun</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="nt">header</span> <span class="p">.</span><span class="nc">theme-toggle</span> <span class="p">.</span><span class="nc">moon</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="kc">none</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">cursor</span><span class="p">:</span> <span class="kc">pointer</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">body</span><span class="p">:</span><span class="nd">not</span><span class="o">(</span><span class="p">.</span><span class="nc">dark-mode</span><span class="o">)</span> <span class="nt">header</span> <span class="p">.</span><span class="nc">theme-toggle</span> <span class="p">.</span><span class="nc">moon</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="kc">inline-block</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">body</span><span class="p">.</span><span class="nc">dark-mode</span> <span class="nt">header</span> <span class="p">.</span><span class="nc">theme-toggle</span> <span class="p">.</span><span class="nc">sun</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="kc">inline-block</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>使用以下的 js 代码来修改 body 的 classlist，实现类别标签的切换</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">changeTheme</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">body</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s1">&#39;body&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">isDarkMode</span> <span class="o">=</span> <span class="nx">body</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nx">toggle</span><span class="p">(</span><span class="s2">&#34;dark-mode&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">localStorage</span><span class="p">.</span><span class="nx">setItem</span><span class="p">(</span><span class="s1">&#39;darkMode&#39;</span><span class="p">,</span> <span class="nx">isDarkMode</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s2">&#34;.theme-toggle&#34;</span><span class="p">).</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;click&#34;</span><span class="p">,</span> <span class="nx">changeTheme</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="loginregiest-登录和注册按钮">Login/Regiest 登录和注册按钮</h3>
<p>简单的两个 Span，使用不同的背景颜色来做区分会使得显示的效果更加的优雅美观，如果设计了这两个按钮，就可能还需要设计登出以及用户 Avater 标签来切换状态。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">nav-func</span> <span class="p">.</span><span class="nc">login</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c">/* border: 1px solid #1fb870; */</span>
</span></span><span class="line"><span class="cl">    <span class="k">font-size</span><span class="p">:</span> <span class="mf">0.9</span><span class="kt">em</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">border-radius</span><span class="p">:</span> <span class="mi">29999</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">padding</span><span class="p">:</span> <span class="mi">5</span><span class="kt">px</span> <span class="mi">5</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">min-width</span><span class="p">:</span> <span class="mi">60</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">text-align</span><span class="p">:</span> <span class="kc">center</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">nav-func</span> <span class="p">.</span><span class="nc">login</span><span class="p">:</span><span class="nd">hover</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">background-color</span><span class="p">:</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">11</span><span class="p">,</span> <span class="mi">29</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">font-weight</span><span class="p">:</span> <span class="kc">bold</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">nav-func</span> <span class="p">.</span><span class="nc">regiest</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">font-size</span><span class="p">:</span> <span class="mf">0.9</span><span class="kt">em</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">border-radius</span><span class="p">:</span> <span class="mi">29999</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">padding</span><span class="p">:</span> <span class="mi">5</span><span class="kt">px</span> <span class="mi">5</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">min-width</span><span class="p">:</span> <span class="mi">67</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">text-align</span><span class="p">:</span> <span class="kc">center</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">background-color</span><span class="p">:</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">color</span><span class="p">:</span> <span class="kc">white</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">nav-func</span> <span class="p">.</span><span class="nc">regiest</span><span class="p">:</span><span class="nd">hover</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">background-color</span><span class="p">:</span> <span class="nb">rgba</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.6</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">font-weight</span><span class="p">:</span> <span class="kc">bold</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="background-背景设计">Background 背景设计</h2>
<blockquote>
<p>用于美观的背景界面在 CSS 中进行编写，如何在页面上放置你的背景，使其较好的展现</p>
</blockquote>
<p>REF：<a href="https://www.freecodecamp.org/chinese/news/html-background-image-how-to-add-wallpaper-images-to-your-website/" target="_blank" rel="noopener">FreeCodeCamp</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">body</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c">/* Set up the background image which fix to the widows view*/</span>
</span></span><span class="line"><span class="cl">    <span class="k">background-image</span><span class="p">:</span> <span class="nb">url</span><span class="p">(</span><span class="s2">&#34;/images/background.jpg&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="c">/* background-image: linear-gradient(-20deg, #2b5876 0%, #4e4376 100%); */</span>
</span></span><span class="line"><span class="cl">    <span class="k">background-size</span><span class="p">:</span> <span class="kc">cover</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">background-repeat</span><span class="p">:</span> <span class="kc">no-repeat</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">background-attachment</span><span class="p">:</span> <span class="kc">fixed</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>为了使得图片适应各种 size 的显示窗口，需要以下的几个关键设置：</p>
<ul>
<li><code>background-repeat: no-repeat;</code> 避免图片小于窗口时出现的复制图片来填满窗口的情况；</li>
<li><code>background-size: cover;</code> 使用 Cover 参数来缩放图片，使得图片得以充满整个窗口；</li>
<li><code>background-attachment: fixed;</code> 确保图片的位置时固定的，避免滚动页面使得图像的位置发生不恰当的变化。</li>
</ul>
<p><strong>设计注意事项</strong>： 一个现实拍摄的背景图片，往往存在比较复杂的色彩分布和细节，而作为背景而言，这样繁杂的色块和元素会给页面布局和色彩设计带来很多困扰，这里推荐的方式是：</p>
<ol>
<li>将背景添加模糊效果，这样能够突出表面的页面元素，包括字体等。</li>
<li>尽量使用大色块的合适图片</li>
<li>图片仅作为类似 Banner 的效果，页面布局整体还是以纯色为主。</li>
</ol>
<h3 id="模糊背景设置">模糊背景设置</h3>
<p>为了设置模糊的背景，主要涉及到的思想为：使用 after 伪元素，在 Background 元素后面添加一层模糊遮罩，并通过 z-index=-1 避免其遮盖住其他元素。</p>
<p>可以使用两种写法，一种使用 filter，直接复制一层元素到原本的元素之上，同时多定义一层背景避免百变。第二种为使用 backdrop-filter，直接对底层背景进行模糊：</p>
<p>使用 filter：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">body</span><span class="p">:</span><span class="nd">after</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">background</span><span class="p">:</span> <span class="kc">inherit</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">filter</span><span class="p">:</span> <span class="nb">blur</span><span class="p">(</span><span class="mi">10</span><span class="kt">px</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">content</span><span class="p">:</span><span class="s1">&#39;&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">position</span><span class="p">:</span><span class="kc">absolute</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">top</span><span class="p">:</span><span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">left</span><span class="p">:</span><span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">width</span><span class="p">:</span> <span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">height</span><span class="p">:</span> <span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-size</span><span class="p">:</span> <span class="kc">cover</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">z-index</span><span class="p">:</span> <span class="mi">-1</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>使用 backdrop-filter：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">body</span><span class="p">:</span><span class="nd">after</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">content</span><span class="p">:</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">position</span><span class="p">:</span> <span class="kc">absolute</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">top</span><span class="p">:</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">left</span><span class="p">:</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">width</span><span class="p">:</span> <span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">height</span><span class="p">:</span> <span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">backdrop-filter</span><span class="p">:</span> <span class="nb">blur</span><span class="p">(</span><span class="mi">10</span><span class="kt">px</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">z-index</span><span class="p">:</span> <span class="mi">-1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="meterial-素材准备和设计">Meterial 素材准备和设计</h2>
<h3 id="tools-形状和背景等">Tools 形状和背景等</h3>
<p><strong>Meterial</strong>: 形状，背景，元素生成</p>
<ul>
<li><a href="https://css-generators.com/" target="_blank" rel="noopener">CSS Generators</a>
：大合集，有诸多 CSS 生成的元素可供参考，丰富自己的页面元素。</li>
<li><a href="https://zhuanlan.zhihu.com/p/654142246" target="_blank" rel="noopener">作为前端开发，你应该知道的这十几个在线免费工具</a>
</li>
<li><a href="https://webgradients.com/?ref=usniemvuilaptrinh" target="_blank" rel="noopener">Gradient Color BG</a>
 using color as your background</li>
<li><a href="https://link.zhihu.com/?target=https%3A//cssgradient.io/" target="_blank" rel="noopener">CSS Gradient — Generator, Maker, and Background</a>
</li>
<li><a href="https://link.zhihu.com/?target=https%3A//www.remove.bg/upload" target="_blank" rel="noopener">Upload Image – remove.bg</a>
: 去除背景，用来做人物剪影等功能</li>
<li><a href="https://www.canva.cn/en/?display-com-option=true" target="_blank" rel="noopener">Logo/Post Design By Canva</a>
: 使用其中的模板来设计自己的 logo 或者海报</li>
<li><a href="getwaves.io/">YourWave</a>
 : 生成浪花分割线，用来做背景等页面元素</li>
<li><a href="https://link.zhihu.com/?target=https%3A//www.blobmaker.app/" target="_blank" rel="noopener">Blobmaker</a>
 :生成水滴</li>
<li><a href="https://link.zhihu.com/?target=https%3A//shadows.brumm.af/" target="_blank" rel="noopener">Smooth Shadow</a>
 : 投影/阴影生成</li>
<li><a href="https://link.zhihu.com/?target=https%3A//bennettfeely.com/clippy/" target="_blank" rel="noopener">Clippy - CSS clip-path maker</a>
 : 生成将图像放在特定形状后面的 CSS 代码</li>
<li><a href="https://link.zhihu.com/?target=https%3A//9elements.github.io/fancy-border-radius/" target="_blank" rel="noopener">Fancy Border Radius Generator</a>
 : 圆角生成器，<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_backgrounds_and_borders/Border-radius_generator" target="_blank" rel="noopener">MDN</a>
 中也有一个</li>
<li><a href="https://app.haikei.app/" target="_blank" rel="noopener">HaiKei</a>
: Sharp Provider, 提供各种生成的形状</li>
<li><a href="https://css-generators.com/ribbon-shapes/" target="_blank" rel="noopener">Ribbon Shapes</a>
: 生成各种飘带</li>
<li><a href="https://picography.co/" target="_blank" rel="noopener">Picography</a>
： upslash 的备胎，免费开源的图片。</li>
<li><a href="https://space.js.org/" target="_blank" rel="noopener">Space</a>
： 3d js 范例</li>
<li><a href="https://calendar-js.com/index.html" target="_blank" rel="noopener">calendar.js</a>
 开源日历 js 组件</li>
</ul>
<p><strong>Character</strong>：角色，插画生成</p>
<ul>
<li><a href="https://peepslab.com/" target="_blank" rel="noopener">PeepsLab</a>
 ：简单一些插图头像生成，主要是肤色、发色、配饰面部等。</li>
<li></li>
</ul>
<p><strong>Charts</strong>：图表生成</p>
<ul>
<li><a href="https://www.magicpattern.design/tools/svg-chart-generator" target="_blank" rel="noopener">SVG Chart Generator</a>
: 生成 Svg 图表，可以根据自己的数据进行定制</li>
<li><a href="https://observablehq.com/plot/getting-started" target="_blank" rel="noopener">Observable Plot</a>
：JS 库，类似 matplotlib 用来画图表</li>
</ul>
<h3 id="color-颜色选择和搭配">Color 颜色选择和搭配</h3>
<p><strong>Color</strong>：主题颜色和颜色搭配选择，结合背景进行页面设计</p>
<ul>
<li><a href="https://colorhunt.co/palette/0926351b42425c83749ec8b9" target="_blank" rel="noopener">colorhunter</a>
：简单的调色板组合</li>
<li><a href="https://colors.lol/" target="_blank" rel="noopener">colors.lol</a>
：简单的调色板组合</li>
<li><a href="https://www.happyhues.co/palettes/10" target="_blank" rel="noopener">happyhues</a>
：一个模板应用各种组合颜色以后的效果展示，非常实用，本身也是一个很美的页面</li>
<li><a href="https://colors.muz.li/" target="_blank" rel="noopener">Color Palette Generator</a>
：调色板组合以及部分样例</li>
<li><a href="https://zhuanlan.zhihu.com/p/520757581" target="_blank" rel="noopener">zhihu-色彩搭配网站分享</a>
：一个调色网站分享的汇总帖子，也是该部分的主要来源</li>
<li><a href="https://venngage.com/tools/accessible-color-palette-generator" target="_blank" rel="noopener">Accessible color palette generator</a>
 : 基于提供的颜色提供调色盘</li>
</ul>
<p>Windows 可以结合 PowerToy 中的取色器来获取壁纸中的主要色彩，进而进行进一步的色彩搭配，功能开启后的快捷键为：win+shift+c</p>
<h3 id="icons-图标文件">Icons 图标文件</h3>
<blockquote>
<p>一个一个图标素材去找显然是一件不现实的事情，图标框架就是为此而生的。</p>
</blockquote>
<p>较为主流常见的图标框架主要有：</p>
<ul>
<li><a href="https://fontawesome.com/" target="_blank" rel="noopener">fontawesome</a>
：</li>
<li><a href="https://ionic.io/ionicons/usage" target="_blank" rel="noopener">ionicons</a>
</li>
<li><a href="https://freeicons.io/search/icons?q=sun" target="_blank" rel="noopener">Free Icons</a>
 : 下载或者复制 svg 代码</li>
<li><a href="https://www.iconhunt.site/?query=next" target="_blank" rel="noopener">Iconhunt</a>
：icon 的搜索引擎，可以搜索到很多开源免费的 svg</li>
<li>element-ui：与框架相关的这里暂时不做研究。</li>
</ul>
<p>其中 <strong>fontawesome</strong> 的使用可以参考<a href="https://www.runoob.com/font-awesome/fontawesome-tutorial.html" target="_blank" rel="noopener">菜鸟教程</a>
 ：可以去官网下载、直接复制 svg，或者使用 stylesheet 引入（<strong>推荐</strong>）来使用对应的图标。</p>
<p>通常使用 <code>&lt;i&gt;</code> 和 <code>&lt;span&gt;</code> 等内联元素进行调用，其中 <code>&lt;i&gt;</code> 尤为，且更为推荐，如：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.css&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">i</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;fa fa-car&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">i</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>ionicons</strong> 的用法则主要就是使用 style 参考：<a href="https://ionic.io/ionicons/usage" target="_blank" rel="noopener">官网</a>
 引入的方式，或者 stylesheet 引入的方式，参考：<a href="https://www.runoob.com/ionic/ionic-icon.html" target="_blank" rel="noopener">菜鸟教程</a>
，图标列表可以查看 <a href="https://ionic.io/ionicons" target="_blank" rel="noopener">Icons</a>
。</p>
<p>使用 defer 或者添加于页面末尾，body 结束之前：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;module&#34;</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.esm.js&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">nomodule</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.js&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>然后再需要图标的地方添加即可：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">ion-icon</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;heart&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">ion-icon</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="template-模板">Template 模板</h3>
<p>Loader : <a href="https://css-loaders.com/classic/" target="_blank" rel="noopener">CSS Loaders</a>
 用于占位的加载动画，只需要赋值粘贴到自己的页面中即可。</p>
<h3 id="fonts-字体文件">Fonts 字体文件</h3>
<blockquote>
<p>这里介绍两种，在线引入字体的资源和本地引入字体的具体操作。</p>
</blockquote>
<h2 id="亚克力材质生成和原理">亚克力材质生成和原理</h2>
<p>ref: <a href="https://medium.com/microsoft-design/diy-a-web-version-the-fluent-design-systems-acrylic-material-fe2eac2a40bb" target="_blank" rel="noopener">DIY: A Web Version of the Fluent Design System’s Acrylic Material</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">backdrop-filter</span><span class="o">:</span> <span class="nt">blur</span><span class="o">(</span><span class="nt">20px</span><span class="o">);</span>  
</span></span><span class="line"><span class="cl"><span class="nt">background-color</span><span class="o">:</span> <span class="nt">rgba</span><span class="o">(</span><span class="nt">255</span><span class="o">,</span><span class="nt">255</span><span class="o">,</span><span class="nt">255</span><span class="o">,</span><span class="p">.</span><span class="nc">3</span><span class="o">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这里的 <code>backgrop-filter</code> 是一个新的 css 特性，能够对元素底下的内容添加模糊效果，也就是一个 filter（为当前元素提供模糊效果）的变体。</p>
<h2 id="简单的响应式设计思路">简单的响应式设计思路</h2>
<p>实现简单的响应式设计实际上就是：</p>
<ul>
<li>确定一些元素的显示与否，简化显示界面，或者将其使用额外弹出界面显示；</li>
<li>结合 overflow 后的行为，避免异常溢出；</li>
<li>确定一些最小最大尺寸和确保定位方式 Work Well，避免在视窗大小发生改变的时候导致元素偏移；</li>
<li>更多的还要用百分比和计算等更多的要素来实现</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>LearnWeb15-CSS09-媒体查询与响应式设计</title>
      <link>https://aikenh.cn/posts/learnweb15-css09-%E5%AA%92%E4%BD%93%E6%9F%A5%E8%AF%A2%E4%B8%8E%E5%93%8D%E5%BA%94%E5%BC%8F%E8%AE%BE%E8%AE%A1/</link>
      <pubDate>Thu, 08 Feb 2024 17:53:55 +0000</pubDate>
      <guid>https://aikenh.cn/posts/learnweb15-css09-%E5%AA%92%E4%BD%93%E6%9F%A5%E8%AF%A2%E4%B8%8E%E5%93%8D%E5%BA%94%E5%BC%8F%E8%AE%BE%E8%AE%A1/</guid>
      <description>&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Responsive_Design&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;响应式设计的历史和思路：&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Media_queries&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;媒介查询的入门 与或非等语句&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;传统的布局方法&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;尽可能使用现代的布局方法，我们可能不需要媒介查询的方式去实现响应式设计了，当然我们也可以结合媒介查询去对现代布局方式做优化。&lt;/p&gt;</description>
      <content:encoded><![CDATA[<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Responsive_Design" target="_blank" rel="noopener">响应式设计的历史和思路：</a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Media_queries" target="_blank" rel="noopener">媒介查询的入门 与或非等语句</a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods" target="_blank" rel="noopener">传统的布局方法</a>
</li>
</ul>
<p>尽可能使用现代的布局方法，我们可能不需要媒介查询的方式去实现响应式设计了，当然我们也可以结合媒介查询去对现代布局方式做优化。</p>
]]></content:encoded>
    </item>
    <item>
      <title>LearnWeb14-CSS08-CSS布局</title>
      <link>https://aikenh.cn/posts/learnweb14-css08-css%E5%B8%83%E5%B1%80/</link>
      <pubDate>Wed, 07 Feb 2024 17:09:44 +0000</pubDate>
      <guid>https://aikenh.cn/posts/learnweb14-css08-css%E5%B8%83%E5%B1%80/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-summary&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Summary&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;这里 CSS 的布局指的是通过控制元素的属性：宽度，高度，块（不同类型），内联等来实现在 HTML 的基础上对整体页面的布局进行调整。将其排布在页面上。&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>这里 CSS 的布局指的是通过控制元素的属性：宽度，高度，块（不同类型），内联等来实现在 HTML 的基础上对整体页面的布局进行调整。将其排布在页面上。</p>

</blockquote>
<blockquote>
<p>CSS 页面布局技术允许我们拾取网页中的元素，并且控制它们相对正常布局流、周边元素、父容器或者主视口/窗口的位置。在这个模块中将涉及更多关于页面<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/Layout_mode" target="_blank" rel="noopener">布局技术</a>
的细节：</p>
</blockquote>
<h2 id="布局模式介绍">布局模式介绍</h2>
<p><a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Normal_Flow" target="_blank" rel="noopener"><strong>正常布局流</strong></a>
：指的是不对页面进行任何布局控制的时候，浏览器默认的 HTML 布局方式，实际上就是按照源码中的先后次序依次出现，在 HTML 布局的过程中，最为重要的就是元素的块和内联两种布局方式。这里需要注意的就是，块的方向和元素的书写方向的关系。</p>
<p>而当我们希望使用 CSS 来改变正常的布局形式的时候，通常会使用以下的一些属性，或者说布局技术，来覆盖掉默认的 HTML 布局行为。</p>
<ul>
<li><strong><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/display" target="_blank" rel="noopener"><code>display</code></a>
</strong> 属性：改变元素在 HTML 中的渲染形式，如 <code>block</code> <code>inline</code> <code>inline-block</code> 还有 CSS 引入的 <a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Grids" target="_blank" rel="noopener">CSS Grid</a>
 和 <a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Flexbox" target="_blank" rel="noopener">Flexbox</a>
.</li>
<li><strong><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/float" target="_blank" rel="noopener"><code>float</code></a>
</strong> 属性：使用 float 属性能改变块级元素换行的特性，实现类似换行的效果，其值指定其他元素围绕块级元素的哪一边。</li>
<li><strong><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/position" target="_blank" rel="noopener"><code>position</code></a>
</strong> 属性：利用 position 来设置盒子在盒子中的位置，在嵌套的情况下就可以产生多样的排布</li>
<li>表格布局：表格的布局方式可以用在非表格内容上，可以使用<code>display: table</code>和相关属性在非表元素上使用</li>
<li>多列布局： <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_multicol_layout" target="_blank" rel="noopener">Multi-column layout</a>
 属性可以让块按列布局，比如报纸的内容就是一列一列排布的。</li>
</ul>
<p>在讨论布局时，<code>display</code> 最多用到的属性为 <code>flex</code> 和 <code>grid</code> 属性，利用这两个属性值来改变布局。</p>
<h3 id="flex-弹性盒子httpsdevelopermozillaorgzh-cndocslearncsscss_layoutflexbox"><a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Flexbox" target="_blank" rel="noopener">flex 弹性盒子</a>
</h3>
<p>弹性盒子的出现为以下的几类问题有一个更好的解决方案：</p>
<ul>
<li>在父内容里面垂直居中一个块内容。</li>
<li>使容器的所有子项占用等量的可用宽度/高度，而不管有多少宽度/高度可用。</li>
<li>使多列布局中的所有列采用相同的高度，即使它们包含的内容量不同。</li>
</ul>
<p>举个例子可能会更加直观，接下来用一个例子说明，flex 最直观的用法：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">container</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="kc">flex</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#39;container&#39;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#39;box0&#39;</span><span class="p">&gt;</span>One<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#39;box1&#39;</span><span class="p">&gt;</span>Two<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#39;box2&#39;</span><span class="p">&gt;</span>Three<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果没有 css 的话，会从上到下排列，但是在父容器上加上 <code>flex</code> 属性以后，就会变成 3 个并排的 box 如下（该控制的方向会随着文字方向）</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240207223841.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240207223841.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240207223841.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ul>
<li>高度会随着最高的一个去设定，排成一行后留下剩下的空白</li>
</ul>
<p>flex 中可以设置许多属性来改变 flex 项在 flex 布局中占用宽/高的方式，允许对块级元素进行拉伸处理，避免在尾部留下空白。例如在上面的例子中，修改 css 如下</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">container</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="kc">flex</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">container</span> <span class="o">&gt;</span> <span class="nt">div</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">flex</span><span class="p">:</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在这种情况下 flex 将会对元素进行拉伸，使其充满整个父容器空间如下：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240207223905.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240207223905.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240207223905.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="grid-网格布局">Grid 网格布局</h3>
<p>当设置 <code>display: grid</code> 时，布局将会改成网格布局，此时还需要用两个辅助属性 <code>grid-template-rows</code> 和 <code>grid-template-columns</code> 分别定义行和列的轨道，从而描绘出理想的网格的情况。</p>
<p>例如：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">wrapper</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="k">grid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-template-columns</span><span class="p">:</span> <span class="mi">1</span><span class="n">fr</span> <span class="mi">1</span><span class="n">fr</span> <span class="mi">1</span><span class="n">fr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-template-rows</span><span class="p">:</span> <span class="mi">100</span><span class="kt">px</span> <span class="mi">100</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-gap</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>columns 定义了 3 个 1fr（fraction） 的列和两个 100px 的行，这样就定义出了如下的网格（2*3），且每个列都是均等的一份，可以简单的描述出将一行分为 3 等分，每个网格占据一份的情况。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240207224538.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240207224538.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240207224538.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>在获得了一个和这样的网格后，我们可能不希望使用所有的网格去放置元素，或者希望有的元素占据多个网格，除了让 html 自动进行排序，我们也可以显示的设置元素的位置。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">wrapper</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="k">grid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-template-columns</span><span class="p">:</span> <span class="mi">1</span><span class="n">fr</span> <span class="mi">1</span><span class="n">fr</span> <span class="mi">1</span><span class="n">fr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-template-rows</span><span class="p">:</span> <span class="mi">100</span><span class="kt">px</span> <span class="mi">100</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-gap</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">box1</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-column</span><span class="p">:</span> <span class="mi">2</span> <span class="o">/</span> <span class="mi">4</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-row</span><span class="p">:</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">box2</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-column</span><span class="p">:</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-row</span><span class="p">:</span> <span class="mi">1</span> <span class="o">/</span> <span class="mi">3</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">box3</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-row</span><span class="p">:</span> <span class="mi">2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-column</span><span class="p">:</span> <span class="mi">3</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><code>grid-column</code> 或者 <code>grid-row</code> 可以设置占据的行或列，以及从哪一行到哪一行 <code>1/3</code> 指的是第一到第三（前闭后开）即第一第二行。这种情况下就会呈现下面的效果：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240207225157.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240207225157.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240207225157.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="float-浮动">Float 浮动</h3>
<p>该属性主要是实现一种 word 文档中的<strong>环绕</strong>的效果，会改变元素身边的流向，其主要有四个取值上下左右：</p>
<ul>
<li><code>left</code>：将本身这个元素浮动到页面的左侧</li>
<li>以此类推</li>
</ul>
<p>例如下述这个代码，及其呈现效果如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">box</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">float</span><span class="p">:</span> <span class="kc">left</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">width</span><span class="p">:</span> <span class="mi">150</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">height</span><span class="p">:</span> <span class="mi">150</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">margin-right</span><span class="p">:</span> <span class="mi">30</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240207225628.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240207225628.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240207225628.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="table-表格布局">Table 表格布局</h3>
<p>使用 <code>display: table</code> 和 <code>display: table-cell</code> 等将父容器和元素转换为格子元素去处理，沿用表格的 layout 来排布我们的元素，可以参考<a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Introduction" target="_blank" rel="noopener">介绍 CSS 布局</a>
 的相关部分。</p>
<h3 id="multi-column-多列布局httpsdevelopermozillaorgzh-cndocslearncsscss_layoutmultiple-column_layout"><a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Multiple-column_Layout" target="_blank" rel="noopener">multi-column 多列布局</a>
</h3>
<p>要把一个块转变成多列容器 (multicol container)，我们可以使用 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/column-count" target="_blank" rel="noopener"><code>column-count</code></a>
 属性来告诉浏览器我们需要多少列，也可以使用<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/column-width" title="Currently only available in English (US)" target="_blank" rel="noopener"><code>column-width</code> (en-US)</a>
来告诉浏览器以至少某个宽度的尽可能多的列来填充容器。</p>
<p>例如以下的例子 <a href="https://developer.mozilla.org/zh-CN/play" target="_blank" rel="noopener">multi-column-layout</a>
 将两个 div 均按照同样的宽度进行多列布局，类似报纸中常用的使用多列来呈现信息。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">body</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">max-width</span><span class="p">:</span> <span class="mi">800</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">margin</span><span class="p">:</span> <span class="mi">0</span> <span class="kc">auto</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">container</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">column-width</span><span class="p">:</span> <span class="mi">300</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">border</span><span class="p">:</span> <span class="mi">5</span><span class="kt">px</span> <span class="kc">solid</span> <span class="kc">black</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">container2</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">column-count</span><span class="p">:</span> <span class="mi">3</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">border</span><span class="p">:</span> <span class="mi">5</span><span class="kt">px</span> <span class="kc">dotted</span> <span class="kc">red</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240207230504.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240207230504.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240207230504.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="position-定位技术">Position 定位技术</h3>
<blockquote>
<p>定位 (positioning) 能够让我们把一个元素从它原本在正常布局流 (normal flow) 中应该在的位置移动到另一个位置。定位 (positioning) 并不是一种用来给你做主要页面布局的方式，它更像是让你去管理和微调页面中的一个特殊项的位置。</p>
</blockquote>
<blockquote>
<p>定位 (positioning) 能够让我们把一个元素从它原本在正常布局流 (normal flow) 中应该在的位置移动到另一个位置。定位 (positioning) 并不是一种用来给你做主要页面布局的方式，它更像是让你去管理和微调页面中的一个特殊项的位置。</p>
</blockquote>
<ul>
<li><strong>静态定位</strong>（Static positioning）是每个元素默认的属性——它表示“将元素放在文档布局流的默认位置——没有什么特殊的地方”。</li>
<li><strong>相对定位</strong>（Relative positioning）允许我们相对于元素在正常的文档流中的位置移动它——包括将两个元素叠放在页面上。这对于微调和精准设计（design pinpointing）非常有用。</li>
<li><strong>绝对定位</strong>（Absolute positioning）将元素完全从页面的正常布局流（normal layout flow）中移出，类似将它单独放在一个图层中。我们可以将元素相对于页面的 <code>&lt;html&gt;</code> 元素边缘固定，或者相对于该元素的_最近被定位祖先元素_（nearest positioned ancestor element）。绝对定位在创建复杂布局效果时非常有用，例如通过标签显示和隐藏的内容面板或者通过按钮控制滑动到屏幕中的信息面板。</li>
<li><strong>固定定位</strong>（Fixed positioning）与绝对定位非常类似，<strong>但是它是将一个元素相对浏览器视口固定</strong>，而不是相对另外一个元素。这在创建类似在整个页面滚动过程中总是处于屏幕的某个位置的导航菜单时非常有用。</li>
<li><strong>粘性定位</strong>（Sticky positioning）是一种新的定位方式，它会让元素先保持和 <code>position: static</code> 一样的定位，当它的相对视口位置（offset from the viewport）达到某一个预设值时，它就会像 <code>position: fixed</code> 一样定位</li>
</ul>
<p>各个定位的例子请参考对应的 MDN 列表，粘性定位和固定定位绝对是我们想要的东西。</p>
<p>这里简单总结以下最重要的一些点：</p>
<ul>
<li>定位除了设置 <code>position: </code> 属性之外，还需要使用 <code>top</code> 和 <code>left</code> 来对位置进行解释。</li>
<li>相对定位时 top 和 left 相当于是于默认偏移相比要远离正常的 top 和 left 的距离</li>
<li>绝对定位的 top 和 left 则是距离页面左侧和顶侧的距离，即 html 元素</li>
<li>固定定位和绝对定位的一样，但是不会随着滚动移动</li>
<li>粘性定位将默认的静态定位 (static positioning) 和固定定位 (fixed positioning) 相混合。当一个元素被指定了 <code>position: sticky</code> 时，它会在正常布局流中滚动，直到它出现在了我们给它设定的相对于容器的位置，这时候它就会停止随滚动移动，就像它被应用了 <code>position: fixed</code> 一样。</li>
</ul>
<h2 id="flex-弹性盒子详解">FLEX 弹性盒子详解</h2>
<p>首先介绍 flex 的模型和一些基本的定义，能够对 flex 的布局调整有更清楚的认知：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240207234612.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240207234612.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240207234612.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ul>
<li><strong>主轴</strong>（main axis）是沿着 flex 元素放置的方向延伸的轴（比如页面上的横向的行、纵向的列）。该轴的开始和结束被称为 <strong>main start</strong> 和 <strong>main end</strong>。</li>
<li><strong>交叉轴</strong>（cross axis）是垂直于 flex 元素放置方向的轴。该轴的开始和结束被称为 <strong>cross start</strong> 和 <strong>cross end</strong>。</li>
<li>设置了 <code>display: flex</code> 的父元素（在本例中是 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/section" target="_blank" rel="noopener"><code>&lt;section&gt;</code></a>
）被称之为 <strong>flex 容器（flex container）。</strong></li>
<li>在 flex 容器中表现为弹性的盒子的元素被称之为 <strong>flex 项</strong>（<strong>flex item</strong>）（本例中是 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/article" target="_blank" rel="noopener"><code>&lt;article&gt;</code></a>
 元素。</li>
</ul>
<h3 id="修改主轴方向">修改主轴方向</h3>
<p>弹性盒子提供了 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/flex-direction" target="_blank" rel="noopener"><code>flex-direction</code></a>
 这样一个属性，它可以指定主轴的方向（弹性盒子子类放置的地方）——它默认值是 <code>row</code>，这使得它们在按你浏览器的默认语言方向排成一排</p>
<h3 id="换行设置">换行设置</h3>
<p>当你在布局中使用定宽或者定高的时候，可能会出现问题即处于容器中的弹性盒子子元素会溢出，可以通过添加换行声明属性，让其自动换行，同时我们也可以限定每个 flex 项的最小宽度，让其不必吧所有都排在同一行，可以多用几行。</p>
<p>在 flex-container 中设置：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">flex-wrap</span><span class="o">:</span> <span class="nt">wrap</span><span class="o">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在 flex-item 中设置：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">flex</span><span class="o">:</span> <span class="nt">200px</span><span class="o">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="flex-flow-缩写">flex-flow 缩写</h3>
<p>可以将 flex-direction 和 flex-wrap 缩写为 flex-flow。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">flex-flow</span><span class="o">:</span> <span class="nt">row</span> <span class="nt">wrap</span><span class="o">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="flex-项的动态尺寸">flex 项的动态尺寸</h3>
<p>flex 计算空间的占用比例的时候使用的是一个无单位的比例值进行表示，例如设置每个 <code>article</code> 的 flex 值为 1，即每个元素占用的空间为 1：1：1 ，<strong>占用的空间</strong>是基于 padding 和 margin 之后剩余的空间计算。</p>
<p>通过调整这个 flex 值可以调整每个值的相对比例，在指定相对值的同时还可以指定 flex-item 的最小值，避免为了并排多个元素导致元素宽度过大或者过小导致异常表现。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">article</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">flex</span><span class="p">:</span> <span class="mi">1</span> <span class="mi">200</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>上述代码将首先为每个 flex 占据 200px 的空间，最后将剩余的空间按照比例分给各个 flex-item，flex 的灵活性就是他最大的优势，对于不同浏览器窗口都能有一个比较好的排布。</p>
<h3 id="flex-的缩写和全写">flex 的缩写和全写</h3>
<p>flex 作为一个简写可以按顺序替代一下的三个属性：</p>
<ul>
<li>flex-grow：实际上就是上述的无单位比例值，</li>
<li>flex-shrink：是一个比较高级的功能，用于溢出容器的 flex 项，预防一些预防情景，一般不用</li>
<li>flex-basis：就是上述用到的最小值。</li>
</ul>
<h3 id="水平和垂直对齐">水平和垂直对齐</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">div</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="kc">flex</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">align-items</span><span class="p">:</span> <span class="kc">center</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">justify-content</span><span class="p">:</span> <span class="kc">space-around</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>上述代码的效果可以让 div 中的元素垂直水平居中，如下图所示：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240208154240.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240208154240.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240208154240.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>其中各个元素的作用如下（如果对名词不清晰的记得去看上述的 flex 模型图）：</p>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/align-items" target="_blank" rel="noopener"><code>align-items</code></a>
：控制 flex-item 在 cross-axis 的位置（也就是垂直位置）。
<ul>
<li>默认是 stretch，也就是从顶开始延伸，然后和最大高度的 item 保持一致。</li>
<li>center 则会使得元素在垂直位置居中，高度和上述保持一致。</li>
<li>也可以设置 <code>flex-start</code> 或者 <code>flex-end</code> 使得元素在最高处或者最低处对齐。</li>
<li>在容器的子元素中可以使用 <code>align-self</code> 属性覆盖 <code>align-iterms</code> 的行为，对其中的特定元素选择特定的位置呈现。</li>
</ul>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/justify-content" target="_blank" rel="noopener"><code>justify-content</code></a>
 ：控制 flex 项在主轴上的位置，默认书写位置的话即水平位置：
<ul>
<li>默认值是 <code>flex-start</code>，从主轴的开始处开始排列，也可以用 <code>flex-end</code></li>
<li><code>center</code> 可以让 flex 项在主轴居中</li>
<li><code>space-around</code> 会使得所有 flex 项沿着主轴均匀的分布，在任意一端留有一点空间</li>
<li><code>space-between</code> 和上述相似，但是不会再两侧留下空间。</li>
</ul>
</li>
</ul>
<h3 id="flex-项排序">flex 项排序</h3>
<p>可以使用 flex 的属性来改变容器中元素显示的顺序，对其中的元素使用 order ；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">button</span><span class="p">:</span><span class="nd">first-child</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">order</span><span class="p">:</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>所有的 flex 项的 order 默认为 0，order 值大的项在显示过程中的顺序更靠后，支持设置负值。</p>
<h3 id="flex-嵌套">flex 嵌套</h3>
<p>flex 允许嵌套使用，当元素为 flex 的时候，其子袁术默认为 flex-item，但是我们可以手动修改 flex-item 项的 display 为 flex，这样其子节点也会变成 flex-item。</p>
<p>支持实现如下的效果:</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240208155347.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240208155347.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240208155347.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>这种情况下使用的代码为：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">article</span><span class="p">:</span><span class="nd">nth-of-type</span><span class="o">(</span><span class="nt">3</span><span class="o">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">flex</span><span class="p">:</span> <span class="mi">3</span> <span class="mi">200</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="kc">flex</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">flex-flow</span><span class="p">:</span> <span class="kc">column</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="grid-网格布局-1">Grid 网格布局</h2>
<p>网格布局是一种很经典且常用的布局模式，可以帮助我们更好的划分页面，获得一个更为统一的页面设计，一个网格通常包含很多行和列，行或者列中间的空隙都被成为沟槽 gutter。</p>
<p>一般网页通常用 12-16 列的网格布局来构成，我们也可参考该布局思路和方式。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240208160449.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240208160449.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240208160449.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>定义网格的时候如果只设置 <code>display: grid</code> 页面不会发生变化因为默认只有一列，需要指定网格的行和列的属性和个数，页面才会相对应的改变。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">div</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="k">grid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-template-columns</span><span class="p">:</span> <span class="mi">200</span><span class="kt">px</span> <span class="mi">200</span><span class="kt">px</span> <span class="mi">200</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如上述 <code>grid-template-columns</code> 按照列的个数为每个列指定了宽度，这里的列值可以是绝对值也可以是各种百分比等任何值，而如果我们希望类似 flex 按照比例来设置的话可以使用 <code>fr</code>，同样还是看占几份 fr 来划分。</p>
<p><strong>fr 如何和其他值并用</strong>：例如和绝对值并用的话会在减掉了绝对值剩下的空间中按照 fr 中所占的比例来进行平等划分。</p>
<h3 id="grid-网格间隙">grid-网格间隙</h3>
<p>使用 <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/column-gap" title="Currently only available in English (US)" target="_blank" rel="noopener"><code>grid-column-gap</code> (en-US)</a>
 属性来定义列间隙；使用 <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/row-gap" title="Currently only available in English (US)" target="_blank" rel="noopener"><code>grid-row-gap</code> (en-US)</a>
 来定义行间隙；使用 <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/gap" title="Currently only available in English (US)" target="_blank" rel="noopener"><code>grid-gap</code> (en-US)</a>
 可以同时设定两者。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">container</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">display</span><span class="p">:</span> <span class="k">grid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">grid-template-columns</span><span class="p">:</span> <span class="mi">2</span><span class="n">fr</span> <span class="mi">1</span><span class="n">fr</span> <span class="mi">1</span><span class="n">fr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">grid-gap</span><span class="p">:</span> <span class="mi">20</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">gap</span><span class="p">:</span> <span class="mi">20</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>网格间隙可以使用 px 或者百分比，但是不能使用 fr 值。</p>
<blockquote>
<p><strong>备注：</strong> <code>gap</code>属性曾经有一个<code>grid-</code>前缀，不过后来的标准进行了修改，目的是让他们能够在不同的布局方法中都能起作用。尽管现在这个前缀不会影响语义，但为了代码的健壮性，你可以把两个属性都写上。</p>
</blockquote>
<h3 id="快速创建重复网格">快速创建重复网格</h3>
<p>假设要创建多个 1fr 的网格，没道理一个个编写，这样太慢且冗余了，可以使用<code>repeat</code>的函数来快速表达：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">container</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="k">grid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-template-columns</span><span class="p">:</span> <span class="nf">repeat</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="n">fr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-gap</span><span class="p">:</span> <span class="mi">20</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>repeat(n, value)表示重复 value 多次，value 也可以是多个值。n 和 value 之间要用 <code>,</code> 隔开，值和值之间则不用。</p>
<h3 id="隐式创建的网格">隐式创建的网格</h3>
<p>可以显示定义行和列，也可以隐式的根据内容自动扩充行网格，这种弥补显式网格无法放下的内容而生成的网格就是隐式网格（或者说被隐式定义的网格），具体的方法如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">container</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="k">grid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-template-columns</span><span class="p">:</span> <span class="nf">repeat</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="n">fr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-auto-rows</span><span class="p">:</span> <span class="mi">100</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-gap</span><span class="p">:</span> <span class="mi">20</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这里设置了行为自动的 100px，这种情况下，当网格内容装不下的时候，就会根据网格内容按照 100px 的高度来自动切分和增加新的网格。</p>
<ul>
<li>该 auto 属性只会适用于隐式定义出来的网格，如果存在显示定义的网格并不会受其影响。</li>
<li>可以使用 minmax 函数来约束隐式网格，<code>minmax(minvalue, auto)</code>，这样我们就约束了网格的最小高度，而没有限制最大高度，这样其会根据内容自动确定行高（且最多只有一行隐式网格）</li>
</ul>
<h3 id="自动多列填充">自动多列填充</h3>
<p>有时候我们希望能够自动生成很多列来填满容器，可以使用下述的代码：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">container</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="k">grid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-template-columns</span><span class="p">:</span> <span class="nf">repeat</span><span class="p">(</span><span class="kc">auto</span><span class="o">-</span><span class="kc">fill</span><span class="p">,</span> <span class="nf">minmax</span><span class="p">(</span><span class="mi">200</span><span class="kt">px</span><span class="p">,</span> <span class="mi">1</span><span class="n">fr</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-auto-rows</span><span class="p">:</span> <span class="nf">minmax</span><span class="p">(</span><span class="mi">100</span><span class="kt">px</span><span class="p">,</span> <span class="kc">auto</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-gap</span><span class="p">:</span> <span class="mi">20</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这里使用了关键字 auto-fill 来代替具体的次数，生成的列最小为 200px 宽。而且容器总会被列塞满。</p>
<h3 id="元素放置">元素放置</h3>
<blockquote>
<p>需要注意的是格子的 index 和对应的文字书写顺序相关，如果使用了如阿拉伯语等非常规的文字书写顺序，需要注意你的 index 是否还适用。</p>
</blockquote>
<p>通常使用 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/grid-column" target="_blank" rel="noopener"><code>grid-column</code></a>
 和 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/grid-row" target="_blank" rel="noopener"><code>grid-row</code></a>
 来定义元素放置的开始格子和结束格子（或所在格子），当然也可以用诸如 <code>grid-column-start</code> 和 <code>grid-column-end</code> 来确定，但是没这个必要。具体的写法如下，开始和结束使用 <code>//</code> 分割。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">header</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-column</span><span class="p">:</span> <span class="mi">1</span> <span class="o">/</span> <span class="mi">3</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-row</span><span class="p">:</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>也可以使用类似 markdown 表格描述的方式来描述元素放置的位置如下:</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">container</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">display</span><span class="p">:</span> <span class="k">grid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-template-areas</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;header header&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;sidebar content&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;footer footer&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-template-columns</span><span class="p">:</span> <span class="mi">1</span><span class="n">fr</span> <span class="mi">3</span><span class="n">fr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">gap</span><span class="p">:</span> <span class="mi">20</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">header</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-area</span><span class="p">:</span> <span class="n">header</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">article</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-area</span><span class="p">:</span> <span class="k">content</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">aside</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-area</span><span class="p">:</span> <span class="n">sidebar</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">footer</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">grid-area</span><span class="p">:</span> <span class="n">footer</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在 grid-template-areas 处定义好每个 var 所在的行列，然后在后续使用 grid-area 将元素放入这些定义好的 var，或者说 area 中即可。</p>
<h2 id="float-浮动布局">FLOAT 浮动布局</h2>
<p>浮动布局这里的使用上文已经介绍过了，基本的使用就是按照这种方式，但是需要注意的是：</p>
<ul>
<li>浮动元素实际上是脱离了原本正常的文档布局流，所以无法使用别的元素的 margin 将浮动元素推开，只能使用浮动元素将其他元素的内容推开。</li>
<li>为浮动元素后的元素添加可视化的背景颜色，可以看到浮动实际上和后面的元素盒子是重合的，缩小的其实是盒子中的行内/内容盒子，才营造出了浮动的效果。 
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240208170326.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240208170326.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240208170326.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</li>
<li>如果我们只希望环绕其中一段文本而非全部，可以为后续的元素添加浮动清除属性，这样后续的元素就会依旧换行在这个元素完全到这个元素之下：
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">cleared</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">clear</span><span class="p">:</span> <span class="kc">left</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c">/* 这里的clear支持left right和both 分别用于取消某一侧的浮动*/</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>如果我们将浮动和文本包裹在同一个 box 中，并添加背景的时候可能会存在下面这种现象：
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240208171303.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240208171303.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240208171303.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
 而我们希望背景的颜色能将浮动元素包裹，这就需要我们取消盒子的浮动，这种情况下比较现代的方法是实用属性：<code>display: flow-root;</code> 
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240208171420.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240208171420.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240208171420.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
 上面背景没覆盖的情况是因为我们在计算 box 背景的时候，由于浮动元素从正常的布局流中脱离出去了，因此计算元素高度的时候并不将其包裹在内，因此可以理解成，需要取消元素之后的盒子的浮动。</li>
</ul>
<h2 id="position-定位">Position 定位</h2>
<p>基本的知识上面已经介绍了，这里不在重复，只添加一些额外的信息和知识点，详细介绍参考 <a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Positioning" target="_blank" rel="noopener">mdn</a>
：</p>
<h3 id="z-index">Z-Index</h3>
<p>该属性主要用于多个元素发生堆叠的时候谁在更上方，当存在多个绝对定位的元素的时候，这一点非常有用，可以为滚动的时候带来不同的效果。</p>
<p>简单的讲，z 轴就是以屏幕到你眼睛的向量为正向，因此 z 轴越大会在最上面，未被设置的时候都默认为 0，设置的时候使用如下代码：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">p</span><span class="p">:</span><span class="nd">nth-of-type</span><span class="o">(</span><span class="nt">1</span><span class="o">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">position</span><span class="p">:</span> <span class="kc">absolute</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">background</span><span class="p">:</span> <span class="kc">lime</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">top</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">right</span><span class="p">:</span> <span class="mi">30</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">z-index</span><span class="p">:</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="绝对定位的父容器设置">绝对定位的父容器设置</h3>
<p>默认是 html 页面的边缘，可以为父容器设置 relative 来实现绝对定位参考的边缘改为父容器。</p>
<h3 id="滚动粘性位置">滚动粘性位置</h3>
<p>每个后续的粘性会替换上一个, 这里目前好像只看到的 dd 和 dt 的方法，别的还没看到，后续值得研究一下。</p>
]]></content:encoded>
    </item>
    <item>
      <title>LearnWeb13-CSS07-CSS开发流程</title>
      <link>https://aikenh.cn/posts/learnweb13-css07-css%E5%BC%80%E5%8F%91%E6%B5%81%E7%A8%8B/</link>
      <pubDate>Wed, 07 Feb 2024 15:54:33 +0000</pubDate>
      <guid>https://aikenh.cn/posts/learnweb13-css07-css%E5%BC%80%E5%8F%91%E6%B5%81%E7%A8%8B/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-summary&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Summary&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;这一章节主要是涵盖开发 css 的各部分，有一些需要掌握的技能的 TODO 还有一些代码风格之类的东西&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>这一章节主要是涵盖开发 css 的各部分，有一些需要掌握的技能的 TODO 还有一些代码风格之类的东西</p>

</blockquote>
<h3 id="todo">TODO</h3>
<ul>
<li><input checked="" disabled="" type="checkbox"> 后续如果初窥门路了可以研究整理一下如何去找参考文献的思路。</li>
<li><input checked="" disabled="" type="checkbox"> 熟练使用使用开发者工具进行网站调试的方式。</li>
</ul>
<h3 id="doc-查找">DOC 查找</h3>
<p>如何查阅 MDN 是一个很重要的技能（当今确实是可以使用 GPT 替代，但是也要掌握基础技能）：</p>
<ul>
<li>当希望知道一个模块有什么属性可以设置的时候应该在 Modules 中查找对应的模块内容，例如<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_table" target="_blank" rel="noopener">表格的相关属性</a>
</li>
<li>当希望属性用法的时候才去查看对应的属性</li>
</ul>
<h3 id="debug-调试">Debug 调试</h3>
<p>尝试熟练去使用开发者模式去查看盒模型，调整颜色，布局，查看属性，添加属性等。</p>
<h3 id="编写规范">编写规范</h3>
<p>可以参考: <a href="https://developer.mozilla.org/zh-CN/docs/MDN/Writing_guidelines/Writing_style_guide/Code_style_guide/CSS" target="_blank" rel="noopener">MDN 的 CSS 代码规范的示例</a>
的同时，遵循<a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Building_blocks/Organizing" target="_blank" rel="noopener">组织 CSS</a>
 的一些准则，来确定自己的编写规范。</p>
<p>我的开发流程：</p>
<ol>
<li>使用 Layer 导入组件库</li>
<li>使用 Layer 设置默认层，包括表格预设，各种预设的东西</li>
<li>使用 Layer 设置主题层</li>
<li>定义 custom 内容，内容的组织可以参考： OOCSS 面向对象的 CSS 设计，或者基于文章结构的组织（基础如 body,h -&gt; 组件，例如不带 index 的列表-&gt; 站点 level 如导航栏 -&gt; 特指内容）</li>
</ol>
<p>编写过程中：</p>
<ul>
<li>保持命名方式统一</li>
<li>添加注释说明各部分内容</li>
<li>保持缩进和换行</li>
<li>为一些颜色之类的数值设置变量，避免重复修改多个地方</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>LearnWeb12-CSS06-表格样式处理</title>
      <link>https://aikenh.cn/posts/learnweb12-css06-%E8%A1%A8%E6%A0%BC%E6%A0%B7%E5%BC%8F%E5%A4%84%E7%90%86/</link>
      <pubDate>Wed, 07 Feb 2024 15:06:05 +0000</pubDate>
      <guid>https://aikenh.cn/posts/learnweb12-css06-%E8%A1%A8%E6%A0%BC%E6%A0%B7%E5%BC%8F%E5%A4%84%E7%90%86/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-summary&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Summary&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;表格的部分主要还是要实操，&lt;a href=&#34;https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Building_blocks/Styling_tables&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;MDN&lt;/a&gt;
 中给了一个例子，这里给我的启示是要更多的去阅读&lt;a href=&#34;https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_table&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;表格的相关属性&lt;/a&gt;
，或者去阅读别人对表格设计中用到的元素，才能更好的掌握一些设计的思路，这里就给出本文中给出的一些常见的属性和设置方法，后续在具体实践中慢慢补充。&lt;/p&gt;

&lt;/blockquote&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;div class=&#34;code-title&#34; onclick=&#34;toggleCode(this)&#34;&gt;
        
        &lt;span class=&#34;code-block-open&#34;&gt;&lt;ion-icon name=&#34;chevron-down-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/span&gt;
        &lt;span class=&#34;code-block-close&#34;&gt;&lt;ion-icon name=&#34;chevron-forward-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/ion-icon&gt;&lt;/span&gt;
        &lt;span&gt;css&lt;/span&gt;
    &lt;/div&gt;
    &lt;div class=&#34;code-content&#34;&gt;
        
        &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;table&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;table-layout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;fixed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;border-collapse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;collapse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;border&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;px&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;solid&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;purple&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;thead&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;th&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;nth-child&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;30&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;thead&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;th&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;nth-child&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;thead&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;th&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;nth-child&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;thead&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;th&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;nth-child&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;35&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;th&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;td&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;padding&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;px&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === &#34;none&#34; || codeContent.style.display === &#34;&#34;) {
        codeContent.style.display = &#34;block&#34;; 
        codeContent.parentNode.classList.remove(&#34;code-has-hidden-child&#34;);
    } else {
        codeContent.style.display = &#34;none&#34;; 
        codeContent.parentNode.classList.add(&#34;code-has-hidden-child&#34;);
    }
}
&lt;/script&gt;&lt;ul&gt;
&lt;li&gt;当为表格设置初始样式的时候，使用 layout 为 fixed 会使得表格的行为更好预测，避免由于内容产生的畸变导致难以设置或者出现一些奇怪对齐情况，使用 fixed 然后设置每一列的宽度，在对内容进行处理可能更好。&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;nth-child&lt;/code&gt; 设置每一列的宽度，最终相加为 100%，使得在不同分辨率下比较好控制。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;border-collapse: collapse;&lt;/code&gt; 原本两个格子之间会有两条边线，这样的话可以合并重叠的边线，让表格更符合我们的预期。&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;text-align&lt;/code&gt; 设置对齐方式&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;thead&lt;/code&gt;，&lt;code&gt;tfoot&lt;/code&gt;，&lt;code&gt;tbody&lt;/code&gt; 来分别设置样式，可以做出类似三线表之类的东西&lt;/li&gt;
&lt;li&gt;为标题 &lt;code&gt;caption&lt;/code&gt; 设置对应的样式&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;后续可能会找一些比较常见的表之类的来整理，&amp;amp; 查看一下组件库。&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>表格的部分主要还是要实操，<a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Building_blocks/Styling_tables" target="_blank" rel="noopener">MDN</a>
 中给了一个例子，这里给我的启示是要更多的去阅读<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_table" target="_blank" rel="noopener">表格的相关属性</a>
，或者去阅读别人对表格设计中用到的元素，才能更好的掌握一些设计的思路，这里就给出本文中给出的一些常见的属性和设置方法，后续在具体实践中慢慢补充。</p>

</blockquote>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">table</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">table-layout</span><span class="p">:</span> <span class="kc">fixed</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">width</span><span class="p">:</span> <span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">border-collapse</span><span class="p">:</span> <span class="kc">collapse</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">border</span><span class="p">:</span> <span class="mi">3</span><span class="kt">px</span> <span class="kc">solid</span> <span class="kc">purple</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">thead</span> <span class="nt">th</span><span class="p">:</span><span class="nd">nth-child</span><span class="o">(</span><span class="nt">1</span><span class="o">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">width</span><span class="p">:</span> <span class="mi">30</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">thead</span> <span class="nt">th</span><span class="p">:</span><span class="nd">nth-child</span><span class="o">(</span><span class="nt">2</span><span class="o">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">width</span><span class="p">:</span> <span class="mi">20</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">thead</span> <span class="nt">th</span><span class="p">:</span><span class="nd">nth-child</span><span class="o">(</span><span class="nt">3</span><span class="o">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">width</span><span class="p">:</span> <span class="mi">15</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">thead</span> <span class="nt">th</span><span class="p">:</span><span class="nd">nth-child</span><span class="o">(</span><span class="nt">4</span><span class="o">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">width</span><span class="p">:</span> <span class="mi">35</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">th</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="nt">td</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">padding</span><span class="p">:</span> <span class="mi">20</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>当为表格设置初始样式的时候，使用 layout 为 fixed 会使得表格的行为更好预测，避免由于内容产生的畸变导致难以设置或者出现一些奇怪对齐情况，使用 fixed 然后设置每一列的宽度，在对内容进行处理可能更好。</li>
<li>使用 <code>nth-child</code> 设置每一列的宽度，最终相加为 100%，使得在不同分辨率下比较好控制。</li>
<li><code>border-collapse: collapse;</code> 原本两个格子之间会有两条边线，这样的话可以合并重叠的边线，让表格更符合我们的预期。</li>
<li>使用 <code>text-align</code> 设置对齐方式</li>
<li>使用 <code>thead</code>，<code>tfoot</code>，<code>tbody</code> 来分别设置样式，可以做出类似三线表之类的东西</li>
<li>为标题 <code>caption</code> 设置对应的样式</li>
</ul>
<p>后续可能会找一些比较常见的表之类的来整理，&amp; 查看一下组件库。</p>
]]></content:encoded>
    </item>
    <item>
      <title>LearnWeb11-CSS05-部分常见样式设置</title>
      <link>https://aikenh.cn/posts/learnweb11-css05-%E9%83%A8%E5%88%86%E5%B8%B8%E8%A7%81%E6%A0%B7%E5%BC%8F%E8%AE%BE%E7%BD%AE/</link>
      <pubDate>Tue, 06 Feb 2024 16:24:17 +0000</pubDate>
      <guid>https://aikenh.cn/posts/learnweb11-css05-%E9%83%A8%E5%88%86%E5%B8%B8%E8%A7%81%E6%A0%B7%E5%BC%8F%E8%AE%BE%E7%BD%AE/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-summary&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Summary&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;该篇章主要收集一些常见的样式设置的参考页和一些需要记住的重要设置内容，由于不可能记住所有的属性和设置，善用查询可能才是唯一的王道。&lt;/p&gt;

&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;css-中的值与单位&#34;&gt;CSS 中的值与单位&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Building_blocks/Values_and_units&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;CSS 中的值与单位&lt;/a&gt;
 这里介绍常见的一些值和单位，有一些新的可能会有所缺失，但是大部分都有了，这里可以列举几个常见但是之前不理解的。&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>该篇章主要收集一些常见的样式设置的参考页和一些需要记住的重要设置内容，由于不可能记住所有的属性和设置，善用查询可能才是唯一的王道。</p>

</blockquote>
<hr>
<h2 id="css-中的值与单位">CSS 中的值与单位</h2>
<p><a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Building_blocks/Values_and_units" target="_blank" rel="noopener">CSS 中的值与单位</a>
 这里介绍常见的一些值和单位，有一些新的可能会有所缺失，但是大部分都有了，这里可以列举几个常见但是之前不理解的。</p>
<ul>
<li><code>em</code> 相对字体大小</li>
<li><code>vw</code> 视窗宽度，值为百分比的含义</li>
<li>百分比：与父辈容器的百分比</li>
<li>rgba 或者 rgb 的第四个值代表透明度，十六进制想设置透明度的话，就在后面再加两位 16 进制表示透明度的百分比。</li>
</ul>
<p>这里倒是提示我们需要有个比较好的取色器或者像 vscode 中的色盘来编写 css，颜色搭配网站在 css 中也是很重要的。</p>
<h2 id="css-调整大小">CSS 调整大小</h2>
<blockquote>
<p>该章节内容来自 <a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS" target="_blank" rel="noopener">MDN 在 CSS 中调整大小</a>
 ，节选。</p>
</blockquote>
<ul>
<li><strong>原始尺寸&amp;固有尺寸:</strong> 如图像等外部资源的固有尺寸；而 div 之类的空元素本身是没有尺寸的（0），其高度由其所含的内容高度决定，这就是元素的固有尺寸；</li>
<li><strong>指定尺寸:</strong> 可以为元素指定 height 和 width，因此当使用绝对值和百分比进行设置尺寸时，如果和内容尺寸不匹配等可能会存在溢出等情况，需要谨慎使用；</li>
</ul>
<p><strong>一、使用百分比设置尺寸</strong>：在使用百分数时，需要知道我们指定的是什么的百分比：</p>
<ul>
<li><strong>百分比通常指可用空间的百分比</strong>：在具体的语境中有，整个<strong>可视空间的百分比</strong>（没有父容器时），或者<strong>父容器宽度的百分比</strong>。</li>
<li>百分比用于内外边距时：其不会根据方向设置为宽或高的百分比，而是固定使用内联尺寸的百分比进行计算，即<strong>宽度的百分比</strong>。</li>
</ul>
<p><strong>二、使用最大最小值设定尺寸</strong>：<code>min-</code> &amp; <code>max-</code> 尺寸，如果我们有一个内容变化的盒子，我们希望固定某个高度或者宽度的最大值或者最小值的情况使用。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">box</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">min-height</span><span class="p">:</span> <span class="mi">150</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">width</span><span class="p">:</span> <span class="mi">200</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>上述例子就拥有一个固定宽度，但是高度随着内容量变化的盒子，这也是一种处理内容溢出的方式；</p>
<p>此外 <code>max-width</code> 还常用于限制图片的大小，避免图片过大导致的显示异常，例如以下用法：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">box</span><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">width</span><span class="p">:</span> <span class="mi">200</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">width</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">max-width</span><span class="p">:</span> <span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">box</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;imgurl&#34;</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;big picture&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#39;width&#39;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">dib</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这种情况下图片会自动限制其表现比例，避免超出 box 的宽度，而无需去手动指定，通过这种方式可以使得图片可相应，避免在更小的设备上显示异常（但是还是应该处理多图片文件，避免过大的图片造成的流量浪费。）</p>
<p><strong>三、使用视口单位设置尺寸:</strong> vw 值的话会反应当前的窗口大小，1vw 指视窗宽度的 1%，直接基于视窗值设置可以获得更为灵活的一些设计，例如可以使用 100vw 来做对应的 banner 或者 nav 等。</p>
<h2 id="css-中常见样式">CSS 中常见样式</h2>
<h3 id="文本">文本</h3>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Styling_text/Fundamentals" target="_blank" rel="noopener">基本文本和字体样式</a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Styling_text/Web_fonts" target="_blank" rel="noopener">web 字体获取和导入</a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/text-align" target="_blank" rel="noopener"><code>text-align</code></a>
 属性可以实现文本居中显示</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/writing-mode" target="_blank" rel="noopener"><code>writing-mode</code></a>
 属性可以修改文字的竖排横排等，该模式也会影响块级元素的 box 的切分方向，参考：<a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Building_blocks/Handling_different_text_directions" target="_blank" rel="noopener">处理不同方向的文本</a>
，在文字修改为竖排的时候 width 和 heigh 也应该切换，为此 css 提供了一种映射属性来处理这种情况，如果需要的话再去了解。</li>
</ul>
<h3 id="列表">列表</h3>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Styling_text/Styling_lists" target="_blank" rel="noopener">列表样式</a>
：包括列表符号，行高，间距，数字的开始和计算..</li>
</ul>
<h3 id="链接">链接</h3>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Styling_text/Styling_links" target="_blank" rel="noopener">链接样式</a>
 ：设置各种状态下的连接表现，设置连接后面添加跳转图标等</li>
</ul>
<h3 id="边框">边框</h3>
<p><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border" target="_blank" rel="noopener"><code>border</code></a>
 圆角设置使用 <code>border-radius</code> 属性进行设置，其通过指定两个值分别定义水平半径和垂直半径来实现，也可以只传入一个值（可为绝对值或者百分比）来设置两个值，其他的参见文档。</p>
<h3 id="背景">背景</h3>
<p><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/background" target="_blank" rel="noopener"><code>background</code></a>
 背景可定义诸多属性，是一个比较复杂的简写属性，这里介绍一些基本能设置的内容，以及简写的规则，背景主要被设置的有：</p>
<ol>
<li>颜色，可以使用 <code>rgba(x,x,x,y)</code> 前三位是颜色代码，最后一位代表透明度。</li>
<li>图片(链接和地址使用 <code>url()</code> 包裹)，可以指定多个图片</li>
<li><code>Background-repeat</code> 设置小图片的平铺，</li>
<li><strong>使用 <code>Background-size</code> 控制图片的大小</strong>，可以使用长度或者百分比，也可以使用 cover（保持比例完全覆盖 box，可能会只显示局部） 或者 contain（保持比例，图片完全在 box 中，可能会留白） 关键字</li>
<li>使用 <code>-position</code> 控制图片的左上角位置，一个水平值和垂直值，可以是值或者 top center 之类的关键字</li>
<li>可以使用 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/gradient" target="_blank" rel="noopener"><code>&lt;gradient&gt;</code></a>
 渐变函数来获得渐变背景</li>
<li>背景附加 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/background-attachment" target="_blank" rel="noopener"><code>background-attachment</code></a>
 控制图片在元素和页面滚动时候的表现
<ol>
<li><code>scroll</code>：使元素的背景在页面滚动时滚动。如果滚动了元素内容，则背景不会移动。实际上，背景被固定在页面的相同位置，所以它会随着页面的滚动而滚动</li>
<li><code>fixed</code>：使元素的背景固定在视口上，这样当页面或元素内容滚动时，它就不会滚动。它将始终保持在屏幕上相同的位置</li>
<li><code>local</code>：将背景固定在它所设置的元素上，所以当你滚动该元素时，背景也随之滚动。</li>
</ol>
</li>
</ol>
<p>简写属性的规则：</p>
<ul>
<li><code>background-color</code> 只能在最后一个逗号之后指定。</li>
<li><code>background-size</code> 值只能立即包含在 <code>background-position</code> 之后，用“/”字符分隔，例如：<code>center/80%</code>。</li>
</ul>
<h2 id="css-中的图像媒体和表单">CSS 中的图像、媒体和表单</h2>
<p><strong>替换元素</strong>：css 中的图像和视频被称为替换元素，css 无法影响他们的内部布局。</p>
<h3 id="图像大小调整">图像大小调整</h3>
<p>前面已经有几种图像大小调整的方式了，这里回顾一下：如果使用 background 属性的处理，使用 max-width 的方式处理；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">box</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="err">...</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-size</span><span class="p">:</span> <span class="kc">cover</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">img</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">max-width</span><span class="p">:</span> <span class="mi">100</span><span class="kt">%</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这里介绍一下其他的处理方式，可以使用 <code>object-fit</code> 属性，可以设置多种将图像嵌入盒子的样式，这里的属性部分和 Background 是重叠的，例如 cover，contain，fill（不会保持比例）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">cover</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">object-fit</span><span class="p">:</span> <span class="kc">cover</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">contain</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">object-fit</span><span class="p">:</span> <span class="kc">contain</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="替换元素的布局特殊性">替换元素的布局特殊性</h3>
<p><strong>替换元素在布局时有特殊表现：<strong>在对替换元素使用 CSS 布局时，例如使用 flex 或者 grid 布局时，<strong>默认元素会被拉伸到布满整块区域</strong>，但是</strong>替换元素不会被拉伸，而是对齐网格区域或者弹性容器的起始处</strong>；</p>
<p>如果希望图像拉伸，我们可以利用下述 css 对 layout 的 image 元素强制拉伸。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">layout</span> <span class="o">&gt;</span> <span class="nt">img</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">height</span><span class="p">:</span> <span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">width</span><span class="p">:</span> <span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="表单-form-元素">表单 <code>form</code> 元素</h3>
<blockquote>
<p>用 CSS 格式化表单元素是一个需要技巧的工作，<a href="https://developer.mozilla.org/zh-CN/docs/Learn/Forms" target="_blank" rel="noopener">HTML 表单指南</a>
包含了详细的格式化表单元素的指导，我不会在这里复述。本节需要介绍的是一些值得关注的关键基础内容。</p>
</blockquote>
<ul>
<li>很多表单控件是通过 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/input" target="_blank" rel="noopener"><code>&lt;input&gt;</code></a>
 元素（html）添加到网页上的。该元素定义了简单的表单区域，例如文字输入。更进一步还有 HTML5 新加入的更加复杂的区域，例如颜色和日期撷取器。</li>
<li><strong>表单元素默认不会继承字体样式</strong>，可以通过在最上面设置 <code>textarea, input, button{font-family: inherit; font-size:100%}</code> 来默认继承</li>
<li><strong>使用 border-box 来设置表单</strong>，由于跨浏览器的 form 元素对于不同的挂件使用不同的盒子约束规则，所有我们可以使用 border-box 来保证统一，然后将内外边距都设置为 0，在设置具体样式的时候再分别添加</li>
<li>为 <code>&lt;textarea&gt;</code> 默认添加 <code>overflow:auto</code> 避免不需要的滚动条。</li>
<li>可以将上述作为我们的表单的默认设置，作为一个层或者最上方添加。</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">button</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="nt">input</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="nt">select</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="nt">textarea</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-family</span><span class="p">:</span> <span class="kc">inherit</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-size</span><span class="p">:</span> <span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">box-sizing</span><span class="p">:</span> <span class="kc">border-box</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">padding</span><span class="p">:</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">margin</span><span class="p">:</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">textarea</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">overflow</span><span class="p">:</span> <span class="kc">auto</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>可以使用下述代码的方式来调整表单的一些样式：</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">input</span><span class="o">[</span><span class="nt">type</span><span class="o">=</span><span class="s2">&#34;text&#34;</span><span class="o">],</span>
</span></span><span class="line"><span class="cl"><span class="nt">input</span><span class="o">[</span><span class="nt">type</span><span class="o">=</span><span class="s2">&#34;email&#34;</span><span class="o">]</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">border</span><span class="p">:</span> <span class="mi">3</span><span class="kt">px</span> <span class="kc">solid</span> <span class="mh">#111</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">margin</span><span class="p">:</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">1</span><span class="kt">em</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">padding</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">width</span><span class="p">:</span> <span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">input</span><span class="o">[</span><span class="nt">type</span><span class="o">=</span><span class="s2">&#34;submit&#34;</span><span class="o">]</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">border</span><span class="p">:</span> <span class="mi">3</span><span class="kt">px</span> <span class="kc">solid</span> <span class="mh">#333</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-color</span><span class="p">:</span> <span class="mh">#000</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">border-radius</span><span class="p">:</span> <span class="mi">5</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">padding</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span> <span class="mi">2</span><span class="kt">em</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-weight</span><span class="p">:</span> <span class="kc">bold</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="mh">#fff</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">input</span><span class="o">[</span><span class="nt">type</span><span class="o">=</span><span class="s2">&#34;submit&#34;</span><span class="o">]</span><span class="p">:</span><span class="nd">hover</span><span class="o">,</span> <span class="nt">input</span><span class="o">[</span><span class="nt">type</span><span class="o">=</span><span class="s2">&#34;submit&#34;</span><span class="o">]</span><span class="p">:</span><span class="nd">focus</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-color</span><span class="p">:</span> <span class="mh">#333</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">form</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;name&#34;</span><span class="p">&gt;</span>Name<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;name&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;email&#34;</span><span class="p">&gt;</span>Email<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;email&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;email&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;buttons&#34;</span><span class="p">&gt;&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;submit&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;Submit&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>至于样式化表单的更加深入的信息，可以看下这些教程的 HTML 一节的这两篇文章：</p>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Learn/Forms/Styling_web_forms" target="_blank" rel="noopener">Styling HTML Forms</a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Learn/Forms/Advanced_form_styling" target="_blank" rel="noopener">Advanced Styling for HTML Forms</a>
</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>LearnWeb10-CSS04-盒子模型</title>
      <link>https://aikenh.cn/posts/learnweb10-css04-%E7%9B%92%E5%AD%90%E6%A8%A1%E5%9E%8B/</link>
      <pubDate>Tue, 06 Feb 2024 15:08:50 +0000</pubDate>
      <guid>https://aikenh.cn/posts/learnweb10-css04-%E7%9B%92%E5%AD%90%E6%A8%A1%E5%9E%8B/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-summary&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Summary&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;HTML 和 CSS 中，所有的元素都是基于一个个的 Box 去渲染的，理解盒子模型的设计，才能知道如何进行布局，从而使的页面按照希望的样子呈现，该定义实际上和 HTML 的块级元素和内联元素使完全相对应的。需要注意两者之间的关联性。&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>HTML 和 CSS 中，所有的元素都是基于一个个的 Box 去渲染的，理解盒子模型的设计，才能知道如何进行布局，从而使的页面按照希望的样子呈现，该定义实际上和 HTML 的块级元素和内联元素使完全相对应的。需要注意两者之间的关联性。</p>

</blockquote>
<h2 id="块级盒子block-box和内联盒子inline-box">块级盒子(Block Box)和内联盒子(Inline Box)</h2>
<p>块级盒子和 HTML 中的块级元素使相互对应的，例如 <code>h</code> 和 <code>p</code> 有以下的特点：</p>
<ul>
<li>与其他元素之间会换行</li>
<li>因为换行，在内联的方向上（也就是行）会占据所有可用空间，即绝大多数情况下和父容器一样宽。</li>
<li>width 和 height 属性均可发挥总用</li>
<li>内边距（padding）, 外边距（margin）和边框（border）会将其他元素从当前盒子周围“推开”</li>
</ul>
<p>内联盒子和 HTML 中的内联元素相互对应，例如 <code>span</code>, <code>em</code>, <code>strong</code> 等，有以下的特点：</p>
<ul>
<li>不会换行</li>
<li>width 和 height 属性不起作用</li>
<li>垂直方向的内边距、外边距以及边框会被应用但是不会把其他处于 <code>inline</code> 状态的盒子推开。</li>
<li>水平方向的内边距、外边距以及边框会被应用且会把其他处于 <code>inline</code> 状态的盒子推开。</li>
</ul>
<p>如果希望切换元素的内联或者块级属性，可以通过对盒子的 display 属性设置进行切换，对应的属性值为 <code>inline</code> 和 <code>block</code>，而更有趣的，如果我们希望不换行，但是内联中的 <code>width</code> 和 <code>height</code> 属性起到作用，可以使用 <code>inline-box</code> 属性。</p>
<blockquote>
<p>Inline-box 属性在导航栏/链接元素中很常见，我们通过增大内容区域来使得链接存在更大的命中区域，同时不影响别的元素的呈现。</p>
</blockquote>
<p>在这里还会看到片一个十分常见的盒子属性 <code>flex</code> 其通常会将外部的显示类型转换为 block，但是内部的显示类型设置为 flex，对其内部的各个子元素，都将转换为 flex 元素，并基于 flex 即<a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Flexbox" target="_blank" rel="noopener">弹性盒子的规则</a>
进行布局，可以生成更灵活的界面，这个后面在排版部分针对性的了解，这里简单介绍如下：</p>
<ul>
<li>flex 会将内部的元素默认沿着行的方向均分切成几个 box，但是具体的切分可以根据后续的属性进行定义。</li>
<li>如果希望 flex 的外部为内联的，则使用 inline-flex 属性。</li>
</ul>
<h3 id="盒子模型">盒子模型</h3>
<p>CSS 中一个块级<strong>标准盒子</strong>包括几个重要的定义，可以结合下面这张图查看，其中蓝色的同样也是可以调整的属性值, 可以很容易的通过浏览器的开发者工具去检查和查看 box 模型：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240206155014.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240206155014.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240206155014.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ul>
<li><strong>Content Box</strong> 区域可以结合 Height 和 Width 属性定义区域大小</li>
<li><strong>Padding Box</strong> 也就是内容区域和边界之间的空白；</li>
<li><strong>Border Box</strong> 边框的范围是在 Content 区域+四周 Padding 指定值得到，包含内容和 padding 区域</li>
<li><strong>Margin Box</strong> 所在的虚线框则是我们的盒子和其他元素之间的空白区域，也可以理解为间隔，使用 Margin 属性定义 Border 和外界的距离</li>
</ul>
<p>也可以使用替代模型去描述一个 box，如果是这种情况就使用 <code>box-sizing: border-box;</code> 处理一个盒子，这种情况下 width 和 height 指的是到 border 的长和宽，这里不多讲，如果希望全部使用原始盒模型可以使用以下的代码：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">html</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">box-sizing</span><span class="p">:</span> <span class="kc">border-box</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">*,</span>
</span></span><span class="line"><span class="cl"><span class="o">*</span><span class="p">::</span><span class="nd">before</span><span class="o">,</span>
</span></span><span class="line"><span class="cl"><span class="o">*</span><span class="p">::</span><span class="nd">after</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">box-sizing</span><span class="p">:</span> <span class="kc">inherit</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="box-的属性设置详解">Box 的属性设置详解</h3>
<p><strong>MARGIN</strong>：详情参考之前的属性简写部分，主要是上左下右四个 margin，这里需要注意的是，其 value 均可为正负值</p>
<ul>
<li>通过负值收缩空间，可以呈现元素相交和堆叠的效果。</li>
<li>通过正值推开空间，令 box 独立呈现。</li>
<li>如果有两个 BOX 相邻等类似的情况，这样两者之间的 Margin 会取 margin-top 和 margin-bottom 中较大的一个，而非相加，需要详解可参阅<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_box_model/Mastering_margin_collapsing" target="_blank" rel="noopener">外边距重叠</a>
</li>
</ul>
<p>Padding：和 Margin 一样，但是不可以为负值。</p>
<p>Border：边框 box 本身和 padding 做区分的原因是因为其主要描绘的是四条边框线，同样可以区分或者共同控制：</p>
<p>分别设置每边的宽度、颜色和样式，可以使用：</p>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-top" target="_blank" rel="noopener"><code>border-top</code></a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-right" target="_blank" rel="noopener"><code>border-right</code></a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-bottom" target="_blank" rel="noopener"><code>border-bottom</code></a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-left" target="_blank" rel="noopener"><code>border-left</code></a>
</li>
</ul>
<p>设置所有边的颜色、样式或宽度，请使用以下属性：</p>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-width" target="_blank" rel="noopener"><code>border-width</code></a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-style" target="_blank" rel="noopener"><code>border-style</code></a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-color" target="_blank" rel="noopener"><code>border-color</code></a>
</li>
</ul>
<p>设置单边的颜色、样式或宽度，可以使用最细粒度的普通属性之一：</p>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-top-width" target="_blank" rel="noopener"><code>border-top-width</code></a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-top-style" target="_blank" rel="noopener"><code>border-top-style</code></a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-top-color" target="_blank" rel="noopener"><code>border-top-color</code></a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-right-width" target="_blank" rel="noopener"><code>border-right-width</code></a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-right-style" target="_blank" rel="noopener"><code>border-right-style</code></a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-right-color" target="_blank" rel="noopener"><code>border-right-color</code></a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-bottom-width" target="_blank" rel="noopener"><code>border-bottom-width</code></a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-bottom-style" target="_blank" rel="noopener"><code>border-bottom-style</code></a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-bottom-color" target="_blank" rel="noopener"><code>border-bottom-color</code></a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-left-width" target="_blank" rel="noopener"><code>border-left-width</code></a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-left-style" target="_blank" rel="noopener"><code>border-left-style</code></a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-left-color" target="_blank" rel="noopener"><code>border-left-color</code></a>
</li>
</ul>
<p>参阅 MDN 文档。</p>
<h3 id="内容溢出处理">内容溢出处理</h3>
<p>当往 box 塞入太多内容的时候可能会导致元素从 Box 边框中溢出，导致呈现效果一团答辩（但是也比消失了好，消失了可能会导致问题没有被发现），css 中通过 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/overflow" target="_blank" rel="noopener"><code>overflow</code></a>
 来控制这些溢出内容：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">box</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="err">...</span>
</span></span><span class="line"><span class="cl">  <span class="k">overflow</span><span class="p">:</span> <span class="kc">hidden</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>默认为 visible 会溢出</li>
<li>设置为 hidden 则会直接截断，</li>
<li>设置为 <code>scroll</code> 浏览器会总是提供滚动条，避免内容的消失（但并不适合所有情况），如果我们仅需在一个方向上滚动，可以使用 overflow-y 仅对 y 轴方向设置溢出处理，不然有两个滚动条可能也不太美观。</li>
<li>设置为 <code>auto</code> 浏览器会仅在内容溢出的时候才会显示滚动条。</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>LearnWeb09-CSS03-层叠层</title>
      <link>https://aikenh.cn/posts/learnweb09-css03-%E5%B1%82%E5%8F%A0%E5%B1%82/</link>
      <pubDate>Tue, 06 Feb 2024 10:48:11 +0000</pubDate>
      <guid>https://aikenh.cn/posts/learnweb09-css03-%E5%B1%82%E5%8F%A0%E5%B1%82/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-summary&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Summary&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;本章节是额外对于优先级的补充章节，在使用上可能会没有明显的感知，但是从概念上理解 CSS 的优先级和后续复杂项目的开发中还是起到了比较大的作用，该章节介绍层叠层的概念，在原先的优先级判定上添加了层的概念。&lt;/p&gt;

&lt;/blockquote&gt;
&lt;h2 id=&#34;层叠概念回顾&#34;&gt;层叠概念回顾&lt;/h2&gt;
&lt;p&gt;该 Section 内容完全摘录自 MDN CSS 教程，也算是对于整体重要性和优先级的一个很好的总结。&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>本章节是额外对于优先级的补充章节，在使用上可能会没有明显的感知，但是从概念上理解 CSS 的优先级和后续复杂项目的开发中还是起到了比较大的作用，该章节介绍层叠层的概念，在原先的优先级判定上添加了层的概念。</p>

</blockquote>
<h2 id="层叠概念回顾">层叠概念回顾</h2>
<p>该 Section 内容完全摘录自 MDN CSS 教程，也算是对于整体重要性和优先级的一个很好的总结。</p>
<ol>
<li><strong>相关声明</strong>：找到所有具有匹配每个元素的选择器的声明代码块。</li>
<li><strong>重要性</strong>：根据规则是普通还是重要对规则进行排序。重要的样式是指设置了 <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/important" title="Currently only available in English (US)" target="_blank" rel="noopener"><code>!important</code> (en-US)</a>
 标志的样式。</li>
<li><strong>来源</strong>：在两个按重要性划分的分组内，按作者、用户或用户代理这几个来源对规则进行排序。</li>
<li><strong>层</strong>：在六个按重要性和来源划分的分组内，按层叠层进行排序。普通声明的层顺序是从创建的第一个到最后一个，然后是未分层的普通样式。对于重要的样式，这个顺序是反转的，但保持未分层的重要样式优先权最低。</li>
<li><strong>优先级</strong>：对于来源层中优先权相同的竞争样式，按<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/Specificity" target="_blank" rel="noopener">优先级</a>
对声明进行排序。</li>
<li><strong>出现顺序</strong>：当两个来源层的优先权相同的选择器具有相同的优先级时，最后声明的具有最高优先级的选择器的属性值获胜。</li>
</ol>
<p>CSS 渲染过程中会逐步往下选择，如果在中间已经决出了胜负就不会继续往下，例如对一个元素在每个来源中只有一个定义，那么在来源层就可以决出胜负，无需往下了，而若获胜的来源中有多个层定义了同个属性，那么就会对比各个层的优先级，诸如此类。</p>
<p>其他的部分前文已经基本提到了，接下来补充来源和层的两个概念。</p>
<blockquote>
<p>![note]+
三个来源中的：&lsquo;用户代理&rsquo;指的是浏览器，用户指的是网站访问者，作者指的是网站开发者，浏览器内部将来自这三个来源的样式表进行来源的排序。</p>
</blockquote>
<h3 id="来源的优先级排序">来源的优先级排序</h3>
<p>有三种<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/Cascade#origin_types" target="_blank" rel="noopener">层叠来源类型</a>
：用户代理样式表、用户样式表和作者样式表。浏览器根据来源和重要性将每个声明分为六个来源分组。有八个优先权级别：六个来源分组、正在过渡的属性和正在动画的属性。优先权的顺序是从具有最低优先权的普通用户代理样式，到当前应用的动画中的样式，到具有最高优先权的重要用户代理样式，再到正在过渡的样式：</p>
<ol>
<li>用户代理普通样式</li>
<li>用户普通样式</li>
<li>作者普通样式</li>
<li>正在动画的样式</li>
<li>作者重要样式</li>
<li>用户重要样式</li>
<li>用户代理重要样式</li>
<li>正在过渡的样式</li>
</ol>
<p>用 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/style" target="_blank" rel="noopener"><code>&lt;style&gt;</code></a>
 元素直接在元素上声明的样式是作者样式。不包括动画和过渡样式，用户代理普通样式具有最低优先权；用户代理重要样式具有最高优先权。</p>
<h3 id="层叠层的概念和作用">层叠层的概念和作用</h3>
<p><strong>概念:</strong> 结合上述两个 section 的内容，我认为层叠层实际上就是引入一个 <code>layer</code> 的概念，在编写 CSS 的时候将规则放到不同的层中，用来更加方便的区分优先级，就想一层一层的给网页刷上样式一样，越往后的优先级默认越高；其中仅有一个例外就是限定了 <code>!important</code> 的规则，他就像是一个占位符，预先确定了某个元素的样式，基于该规则进行&quot;拓展&quot;，因此其越早出现优先级越高。</p>
<p><strong>作用:</strong></p>
<ul>
<li>通过这种方式便于多人同时开发时的协作，复杂项目时的持续开发和维护等，也以一种类似分桶的方式便于 Debug 样式的问题，使得 CSS 的逻辑更加清晰。</li>
<li>层叠层中还允许创建嵌套层，例如每个人使用的组件库不同时，可以各自将组件库嵌入自己的层中，消除组件库的定义与其他人的样式冲突，同时也确保开发过程中能够方便的使用和调整组件库而无需考虑优先级。</li>
</ul>
<p>因此具体使用的时候，我们可以使用嵌套层的方式，将默认样式、第三方组件、主题等等首先嵌入层中，然后在开始继续的开发，这样在处理优先级的时候我们就无需考虑也无需解决跨层的冲突。</p>
<h2 id="层叠层使用">层叠层使用</h2>
<ul>
<li>使用 <code>@layer</code> 声明 at 规则，使用 <code>@layer</code> 后跟一个或者多个层的名称来声明层，这将创建一个没有任何样式的具名层；</li>
<li>使用 <code>@layer</code> 块 at 规则，在快中的所有样式都将添加到一个命名或者未命名的层中</li>
<li>使用具有 <code>layer</code> 关键字或 <code>layer()</code> 函数的 <code>@import</code> 规则，将导入文件的内容分配到该层中。</li>
</ul>
<p>在尚未初始化具有相同名称的层的情况下，这三种方法中的任何一种都会创建一个层。如果在 <code>@layer</code> at 规则或带有 <code>layer()</code> 的 <code>@import</code> 中没有提供层名称，则将创建一个新的匿名层。</p>
<p>1-2 的区别实际上就是先声明或者带初始值声明，例如以下的 cpp 代码</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// 第一种
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">a_arr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">a_arr</span><span class="p">.</span><span class="n">push_back</span><span class="p">({</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 第二种
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">a_arr</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">};</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>备注：</strong> 层的优先顺序是它们创建的顺序。不在层中的样式，或者称为“未分层样式”，会层叠到最终的隐式标签中。</p>
<h3 id="使用-layer-声明-at-规则">使用 <code>@layer</code> 声明 at 规则</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">@</span><span class="k">layer</span> <span class="nt">theme</span><span class="o">,</span> <span class="nt">components</span><span class="o">,</span> <span class="nt">default</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>通常在 CSS 的第一行进行层的声明，避免有些规则漏掉导致没办法使用层完全控制样式的优先级，上述层的出现顺序即是声明的顺序，可以看到我们是先刷了一层主题，再往上刷组件，刷默认值，最后剩下的是我们最后自定义和调整的内容（未添加到具体名称里的会自动添加到匿名层中，且最后定义）。</p>
<p>此外需要注意的是，如果上述三个层并非放在最上方，而且有一些层已经被定义了，那么被定义的层在这里不会再次声明，而只会被忽略，剩下的层将添加在已有的层之后，所以推荐还是在最前面定义。</p>
<h3 id="使用-layer-块-at-规则添加具体的样式">使用 <code>@layer</code> 块 at 规则添加具体的样式</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">@</span><span class="k">layer</span> <span class="nt">theme</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nt">main</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="k">display</span><span class="p">:</span> <span class="k">grid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>使用块 at 规则可以：创建层并将块内的样式初始化添加进该层。如果没有指定 theme 名称的话，则会创建匿名层，每次未命名都会创建一个新的匿名层，而不是共用同个匿名层，这些匿名层也没办法往里面添加样式了。</p>
<h3 id="使用媒体查询来创建层">使用媒体查询来创建层</h3>
<p>同样考虑到不同的设备尺寸，让我们通过媒体查询来决定是否定义某些层，这样也可以用来做页面的响应式设计，在不同的设备上生效不同的层即可，具体的代码范例如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">@</span><span class="k">media</span> <span class="o">(</span><span class="nt">min-width</span><span class="o">:</span> <span class="nt">50em</span><span class="o">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="p">@</span><span class="k">layer</span> <span class="nt">site</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">@</span><span class="k">layer</span> <span class="nt">page</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">h1</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">text-decoration</span><span class="p">:</span> <span class="kc">overline</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">color</span><span class="p">:</span> <span class="kc">red</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">@</span><span class="k">layer</span> <span class="nt">site</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">h1</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">text-decoration</span><span class="p">:</span> <span class="kc">underline</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">color</span><span class="p">:</span> <span class="kc">green</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这样在宽屏上，事先定义的则是 site，否则为 page，这样就会使得样式发生变化，从而实现页面的响应式设计。</p>
<h3 id="使用-import-将样式表导入层">使用 <code>@import</code> 将样式表导入层</h3>
<blockquote>
<p>这一部分直接节选自 MDN，描述得很清楚了。</p>
</blockquote>
<p><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/@import" target="_blank" rel="noopener"><code>@import</code></a>
 规则允许用户直接从其他样式表导入样式规则到 CSS 文件或 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/style" target="_blank" rel="noopener"><code>&lt;style&gt;</code></a>
 元素中。</p>
<p>导入样式表时，必须在样式表或 <code>&lt;style&gt;</code> 块中的任何 CSS 样式之前定义 <code>@import</code> 语句。<code>@import</code> 语句必须出现在最前面，在任何样式之前，但可以在创建一个或多个层而不向这些层分配任何样式的 <code>@layer</code> 规则之后（<code>@import</code> 也可以在 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/@charset" target="_blank" rel="noopener"><code>@charset</code></a>
 规则之后）。</p>
<p>你可以将样式表导入具名层、嵌套具名层或匿名层。以下层分别将样式表导入 <code>components</code> 层、<code>components</code> 层中的嵌套 <code>dialog</code> 层和一个未命名层：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">@</span><span class="k">import</span> <span class="nt">url</span><span class="o">(</span><span class="s2">&#34;components-lib.css&#34;</span><span class="o">)</span> <span class="nt">layer</span><span class="o">(</span><span class="nt">components</span><span class="o">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">@</span><span class="k">import</span> <span class="nt">url</span><span class="o">(</span><span class="s2">&#34;dialog.css&#34;</span><span class="o">)</span> <span class="nt">layer</span><span class="o">(</span><span class="nt">components</span><span class="p">.</span><span class="nc">dialog</span><span class="o">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">@</span><span class="k">import</span> <span class="nt">url</span><span class="o">(</span><span class="s2">&#34;marketing.css&#34;</span><span class="o">)</span> <span class="nt">layer</span><span class="o">()</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这里注意层的嵌套使用的是 <code>.</code> 符号，无论是命名，引用，添加样式表到该嵌套层，都使用的这个符号，使用 import 导入的嵌套层会默认在该层的末尾，吧    但是在同层中，非嵌套的样式会优先于普通嵌套的样式，嵌套层之间的优先级则基于顺序决定。</p>
<p>你可以将多个 CSS 文件导入到单个层中。以下声明将两个单独的文件导入到单个 <code>social</code> 层中：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">@</span><span class="k">import</span> <span class="nt">url</span><span class="o">(</span><span class="nt">comments</span><span class="p">.</span><span class="nc">css</span><span class="o">)</span> <span class="nt">layer</span><span class="o">(</span><span class="nt">social</span><span class="o">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">@</span><span class="k">import</span> <span class="nt">url</span><span class="o">(</span><span class="nt">sm-icons</span><span class="p">.</span><span class="nc">css</span><span class="o">)</span> <span class="nt">layer</span><span class="o">(</span><span class="nt">social</span><span class="o">)</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>你可以使用<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_media_queries/Using_media_queries" target="_blank" rel="noopener">媒体查询</a>
和<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_conditional_rules/Using_feature_queries" target="_blank" rel="noopener">特性查询</a>
根据特定条件导入样式并创建层。以下将样式表导入到 <code>international</code> 层，但前提是浏览器支持 <code>display: ruby</code>，而且被导入的文件取决于屏幕的宽度。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">@</span><span class="k">import</span> <span class="nt">url</span><span class="o">(</span><span class="s2">&#34;ruby-narrow.css&#34;</span><span class="o">)</span> <span class="nt">layer</span><span class="o">(</span><span class="nt">international</span><span class="o">)</span> <span class="nt">supports</span><span class="o">(</span><span class="nt">display</span><span class="o">:</span> <span class="nt">ruby</span><span class="o">)</span> <span class="nt">and</span>
</span></span><span class="line"><span class="cl">  <span class="o">(</span><span class="nt">width</span> <span class="o">&lt;</span> <span class="nt">32rem</span><span class="o">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">@</span><span class="k">import</span> <span class="nt">url</span><span class="o">(</span><span class="s2">&#34;ruby-wide.css&#34;</span><span class="o">)</span> <span class="nt">layer</span><span class="o">(</span><span class="nt">international</span><span class="o">)</span> <span class="nt">supports</span><span class="o">(</span><span class="nt">display</span><span class="o">:</span> <span class="nt">ruby</span><span class="o">)</span> <span class="nt">and</span>
</span></span><span class="line"><span class="cl">  <span class="o">(</span><span class="nt">width</span> <span class="o">&gt;=</span> <span class="nt">32rem</span><span class="o">)</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="层的优先级">层的优先级</h3>
<p>整体判断优先级的逻辑和之前整理的是一致的，这里就简单给一下 MDN 中提到的总结。</p>
<ul>
<li>层的优先权顺序是创建层的顺序。</li>
<li>一旦创建，就无法更改层顺序。</li>
<li>普通样式的层优先权是创建层的顺序。</li>
<li>未分层普通样式优先于有层普通样式。</li>
<li>重要样式的层优先权被反转，早期创建的层具有优先权。</li>
<li>所有有层的重要样式都优先于未分层的重要（和普通）样式。</li>
<li>普通内联样式优先于所有普通样式，无论是否分层。</li>
<li>重要内联样式优先于所有其他样式，正在过渡的样式除外。</li>
<li>作者样式无法覆盖重要内联样式（过渡除外，但这是临时的）</li>
</ul>
<p>嵌套层的层叠优先权顺序与常规层类似，但包含在层内。优先权顺序基于嵌套层创建的顺序。<strong>层中的非嵌套样式优先于嵌套的普通样式</strong>，对于重要样式则相反。嵌套层之间的优先级权重并不重要，但它在嵌套层内的冲突样式中确实很重要。</p>
]]></content:encoded>
    </item>
    <item>
      <title>LearnWeb08-CSS02-CSS入门</title>
      <link>https://aikenh.cn/posts/learnweb08-css02-css%E5%85%A5%E9%97%A8/</link>
      <pubDate>Sun, 04 Feb 2024 17:05:12 +0000</pubDate>
      <guid>https://aikenh.cn/posts/learnweb08-css02-css%E5%85%A5%E9%97%A8/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-note&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Note&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;&lt;ol&gt;
&lt;li&gt;你永远无法记住所有的 CSS 属性，善用参考资料：&lt;a href=&#34;https://developer.mozilla.org/zh-CN/docs/Web/CSS/Reference&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;MDN CSS reference&lt;/a&gt;
 和 GPT&lt;/li&gt;
&lt;li&gt;善用浏览器的开发者面板在页面上及时编辑 CSS。&lt;/li&gt;
&lt;/ol&gt;

&lt;/blockquote&gt;
&lt;h2 id=&#34;css-运行逻辑&#34;&gt;CSS 运行逻辑&lt;/h2&gt;
&lt;p&gt;前面在 &lt;a href=&#34;tmp/LearnWeb00-Web%e5%85%a5%e9%97%a8.md&#34;&gt;LearnWeb00-Web入门&lt;/a&gt;
 中简单提及了浏览器以及 CSS 起了什么作用，这里则是对于 CSS 是如何具体参与进页面的渲染的讲解，包括早该知道的 DOM 的定义也会在这里介绍，是 &lt;a href=&#34;https://developer.mozilla.org/zh-CN/docs/Learn/CSS/First_steps/How_CSS_works&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;CSS 是如何运行&lt;/a&gt;
的读书笔记。&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-note">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Note</span>
  </p>
  <p><ol>
<li>你永远无法记住所有的 CSS 属性，善用参考资料：<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/Reference" target="_blank" rel="noopener">MDN CSS reference</a>
 和 GPT</li>
<li>善用浏览器的开发者面板在页面上及时编辑 CSS。</li>
</ol>

</blockquote>
<h2 id="css-运行逻辑">CSS 运行逻辑</h2>
<p>前面在 <a href="tmp/LearnWeb00-Web%e5%85%a5%e9%97%a8.md">LearnWeb00-Web入门</a>
 中简单提及了浏览器以及 CSS 起了什么作用，这里则是对于 CSS 是如何具体参与进页面的渲染的讲解，包括早该知道的 DOM 的定义也会在这里介绍，是 <a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/First_steps/How_CSS_works" target="_blank" rel="noopener">CSS 是如何运行</a>
的读书笔记。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240205140358.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240205140358.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240205140358.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>浏览器获取了 HTML 之后：</p>
<ol>
<li>会拉取其所依赖的所有 CSS，JS 和静态资源（Parser HTML）</li>
<li>解析 HTML 代码，根据其中的 Tag、Class、ID 和相互之间的关系将 HTML 解析成 DOM ，每个元素作为其中的一个节点放进相对应的桶中。（元素桶、ID 桶之类）</li>
</ol>
<p>紧接着，在拉取完 CSS 之后，浏览器开始解析 CSS，基于 CSS 中的选择器找到每个样式所属的 DOM 节点，并将其添加进去。</p>
<p>最后基于最终的 DOM(Document Object Model) 渲染出完整的页面，这里对 DOM 进行一个简单的解释：</p>
<blockquote>
<p>一个 DOM 有一个树形结构，标记语言中的每一个元素、属性以及每一段文字都对应着结构树中的一个节点（Node/DOM 或 DOM node）。节点由节点本身和其他 DOM 节点的关系定义，有些节点有父节点，有些节点有兄弟节点（同级节点）。</p>
</blockquote>
<p>此外浏览器在渲染过程中如果遇到了位置的 CSS 会直接跳过相应的 CSS ，然后渲染下一个规则。</p>
<h2 id="规则">@规则</h2>
<p>@rules(at-rules)是一类特殊的规则，&ldquo;提供了关于 CSS 应该执行什么或如何表现的指令&rdquo;。具体而言主要有以下两类：</p>
<p>第一类：引入别的样式文件</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">@</span><span class="k">import</span> <span class="s2">&#34;style/style2.css&#34;</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>第二类：引入<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_media_queries" target="_blank" rel="noopener">媒体查询</a>
，按照媒体的样式（例如视窗的大小）来决定使用的样式，这一点也是为了响应式布局很重要的一点；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">body</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-color</span><span class="p">:</span> <span class="kc">pink</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">@</span><span class="k">media</span> <span class="o">(</span><span class="nt">min-width</span><span class="o">:</span> <span class="nt">30em</span><span class="o">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">body</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">background-color</span><span class="p">:</span> <span class="kc">blue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>当窗口（可以通过调整浏览器宽度来改变）宽度&gt;30em 时使用另外的背景颜色。</p>
<h2 id="代码添加空白">代码添加空白</h2>



  
  

<blockquote class="alert-blockquote alert-quota">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Quota</span>
  </p>
  <p>空白是指实际的空格、制表符和换行符。就像浏览器忽略了 HTML 中的空白一样，浏览器也忽略了 CSS 中的空白。空白的价值在于它可以提高可读性。</p>

</blockquote>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">body</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">font</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="mi">1</span><span class="kt">em</span><span class="o">/</span><span class="mi">150</span><span class="kt">%</span> <span class="n">Helvetica</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">Arial</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="kc">sans-serif</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">padding</span><span class="p">:</span> <span class="mi">1</span><span class="kt">em</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">margin</span><span class="p">:</span> <span class="mi">0</span> <span class="kc">auto</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">max-width</span><span class="p">:</span> <span class="mi">33</span><span class="kt">em</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">@</span><span class="k">media</span> <span class="o">(</span><span class="nt">min-width</span><span class="o">:</span> <span class="nt">70em</span><span class="o">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">body</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">font-size</span><span class="p">:</span> <span class="mi">130</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以使用 format 插件来对代码进行重构，增强代码的可读性。但是记得空白也不是随便用的，比如简写属性中的空白就用来区分不同的属性值，对于名称中的空白切分也会导致异常。</p>
<h2 id="属性与值进阶">属性与值进阶</h2>
<p>大多数情况下属性的值为关键词或者数值，但是也会有一些较为复杂的场景存在，例如简单的一些函数。</p>
<h3 id="calc-函数">Calc() 函数</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">outer</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">border</span><span class="p">:</span> <span class="mi">5</span><span class="kt">px</span> <span class="kc">solid</span> <span class="kc">black</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">box</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">padding</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">width</span><span class="p">:</span> <span class="nb">calc</span><span class="p">(</span><span class="mi">90</span><span class="kt">%</span> <span class="o">-</span> <span class="mi">30</span><span class="kt">px</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-color</span><span class="p">:</span> <span class="kc">rebeccapurple</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="kc">white</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;outer&#34;</span><span class="p">&gt;&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;box&#34;</span><span class="p">&gt;</span>内部盒子的宽度为 90% - 30px。<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>上述的 width 使用 calc 将宽度表达为 90% - 30 像素，使用 Calc 可以执行一些简单的数值计算流程。</p>
<h3 id="transform-函数">Transform 函数</h3>
<p>transform 属性通常用于图像变形，因此其取值通常为一些函数，这里以 rotate 为例。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class:</span><span class="err">&#34;</span><span class="na">box</span><span class="err">&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">box</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">margin</span><span class="p">:</span> <span class="mi">30</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">width</span><span class="p">:</span> <span class="mi">100</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">height</span><span class="p">:</span> <span class="mi">100</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">background-color</span><span class="p">:</span> <span class="kc">rebeccapurple</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="err">transform=rotate(0.8turn)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>上述代码会得到一个旋转后的 box，诸如此类，<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/transform" target="_blank" rel="noopener">Transform</a>
 还有一些别的常用函数，后续可能会比较频繁的遇到，同样可以在 MDN 查询。</p>
<h3 id="简写属性">简写属性</h3>



  
  

<blockquote class="alert-blockquote alert-quota">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Quota</span>
  </p>
  <p>一些属性，如 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/font" target="_blank" rel="noopener"><code>font</code></a>
、<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/background" target="_blank" rel="noopener"><code>background</code></a>
、<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/padding" target="_blank" rel="noopener"><code>padding</code></a>
、<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border" target="_blank" rel="noopener"><code>border</code></a>
 和 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/margin" target="_blank" rel="noopener"><code>margin</code></a>
 等属性称为<strong>简写属性</strong>。它们允许在一行中设置多个属性值，从而节省时间并使代码更整洁。</p>

</blockquote>
<p>典型的例子就是边框定义，需要定义四个方向的边框，如 <code>padding-top</code> 和 <code>padding-bottom</code>，可以使用 <code>padding</code> 直接定义四个值来节省时间，<strong>顺序为顺时针（上右下左）</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">padding</span><span class="o">:</span> <span class="nt">10px</span> <span class="nt">15px</span> <span class="nt">15px</span> <span class="nt">5px</span><span class="o">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>更多的可以参考 MDN 的 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/Reference" target="_blank" rel="noopener">CSS 参考页面</a>
，找到更多简写资源如：<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/background" target="_blank" rel="noopener">background</a>
</p>
<h2 id="选择器进阶">选择器进阶</h2>
<p>基础 CSS 规则中介绍了一些基本的选择器类别，这里为选择器做相对进阶的介绍，包括一些选择器的组合和运算，一些其他的用法，还有一些特别的选择器。</p>
<h3 id="同时选择多个元素">同时选择多个元素</h3>
<p>如果要选择多个类型的元素并为他们添加同一种规则集，可以使用 <code>，</code> 对不同元素进行分割如下。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">p</span><span class="o">,</span><span class="nt">li</span><span class="o">,</span><span class="nt">h1</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="kc">red</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>上述代码会将列表，大标题，普通段落都使用红色渲染。</p>
<h3 id="伪类选择器理解">伪类选择器理解</h3>
<p>参考<a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements" target="_blank" rel="noopener">伪类和伪元素</a>
，伪类选择器的名称可能会让人困惑，实际上可以理解为一些状态或者一些辅助类别，可能是选择<strong>在特定状态</strong>下的某些元素，举个例子，链接点击前后的不同颜色：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">a</span><span class="p">:</span><span class="nd">link</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">color</span><span class="p">:</span> <span class="kc">pink</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">a</span><span class="p">:</span><span class="nd">visited</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">color</span><span class="p">:</span> <span class="kc">grey</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>或者一些父子节点关系，如<strong>选择元素的某一个部分而不是整个元素</strong>，下面的例子选择 article 中作为第一个 child 的 p 元素，通常为第一段</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">article</span> <span class="nt">p</span><span class="p">:</span><span class="nd">first-child</span><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>或者用一些选择特定子节点的伪类 <code>:nth-child(even)</code>，括号内接 index 为特定的子元素，也可以用 even 和 odd 指定奇偶，有特殊需求的时候可以去查表或者查 Chatgpt。</p>
<h3 id="伪元素选择器">伪元素选择器</h3>
<p>参考<a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements" target="_blank" rel="noopener">伪类和伪元素</a>
有一些特殊的元素，描述了一些特别的状态，例如：</p>
<ul>
<li><code>::first-line</code>:选中第一行的内容</li>
<li><code>::before</code>: 在所有内容之前添加，可以插入一些辅助图标等</li>
<li><code>::after</code>:在所有内容之后添加，可以插入一些辅助图表等</li>
</ul>
<p>举个例子，选择 article 部分的第一段的第一行：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">article</span> <span class="nt">p</span><span class="p">:</span><span class="nd">first-child</span><span class="p">::</span><span class="nd">first-line</span><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="选择器组合方法">选择器组合方法</h3>
<ul>
<li><strong>元素和类选择器嵌套</strong>：如果使用了 <code>p.my-class</code> 作为选择器，含义是只选择 p 元素中类名为 my-class 的元素，这个时候 a 元素的 my-class 就会被忽略。</li>
<li><strong>类选择器嵌套</strong>：如果使用了 <code>.log.warning</code> 作为选择器，则会选择出 log 类中的 warning 类的元素，这里补充一个知识，就是 HTML 一个元素定义多个类的方式 <code>&lt;p class=&quot;log warning&quot;&gt;</code> 使用空格分割</li>
<li>使用空格<strong>后代选择</strong>：下述代码的选择器会选中 list 中的所有 em 元素，不在 list 中的 em 元素会被忽略，使用方法是基于先后顺序，以及使用空格分开。</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">li</span> <span class="nt">em</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">color</span><span class="p">:</span><span class="kc">red</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>使用 <code>+</code> <strong>相邻选择</strong>符：下述代码会选中与 <code>h1</code> 相邻的 <code>p</code> 中的 <code>span</code> 元素</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">h1</span> <span class="o">+</span> <span class="nt">p</span> <span class="nt">span</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">font-size</span><span class="p">:</span> <span class="mi">200</span><span class="kt">%</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="kc">red</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>使用 <code>&gt;</code> <strong>子代关系选择符</strong>：只会选中子代，孙代及以上的不会被选中</li>
<li>使用 <code>~</code> <strong>兄弟关系选择符</strong>：举个例子，下述代码会选中 h1 之后的所有 p 元素。</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">h1</span> <span class="o">~</span> <span class="nt">p</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="全局选择器-">全局选择器 <code>*</code></h3>
<p><code>*</code> 全局选择器，选中文档中的所有内容（或者是父元素中的全部内容），通常用于和其他元素组合，避免一些选择器组合中的歧义，例如和伪类选择器组合，选择第一个子元素的情况。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">article</span> <span class="p">:</span><span class="nd">first-child</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>上述代码用来选择 article 中的第一个子元素，但是该写法容易和下述写法混淆</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">article</span><span class="p">:</span><span class="nd">first-child</span><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>而该写法表示的则是任何作为第一个子元素的 article 元素，意义上完全不同，因此为了可读性和可维护性，建议引入全局变量如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">article</span> <span class="o">*</span><span class="p">:</span><span class="nd">first-child</span><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>表达了作为 article 元素中第一个子元素的任何元素，则符合我们的需求，也不容易产生混淆。</p>
<h3 id="属性选择器">属性选择器</h3>
<p>属性选择器引入了部分正则的语法，可以较为灵活的判断属性值是否（以某种形式）包含了某个 Value，基础的语法如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="o">[</span><span class="nt">attr</span><span class="o">]</span><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>该语句选择具有 <code>[attr]</code> 属性的所有元素，当然也可以和其他的选择器做组合，这里后续不在赘述。</p>
<p>如果需要指定 attr 的值，有以下的多种方式：</p>
<ul>
<li><code>[attr=value]</code>: 存在只有一个且正好相等</li>
<li><code>[attr^=value]</code>: 存在至少一个以 value 开头的属性</li>
<li><code>[attr$=value]</code>: 存在至少一个以 value 结尾的属性</li>
<li><code>[attr*=value]</code>: 存在至少一个含有 value 的属性</li>
<li><code>[attr~=value]</code>: 完全相等或者包含一个 value</li>
<li><code>[attr|=value]</code>: 匹配 value 或者以 value 加连字符开头的属性值</li>
<li>&hellip;</li>
</ul>
<p>如果希望属性值大小写不敏感，可以添加 i 如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="o">[</span><span class="nt">attr</span> <span class="nt">i</span><span class="o">]</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="页面样式渲染逻辑">页面样式渲染逻辑</h2>
<p>会有同个元素被多个选择器渲染的情况，这种情况下会基于<strong>层叠</strong>（cascade）和<strong>优先级</strong>（specificity）规则对元素进行渲染。</p>
<h3 id="样式渲染规则">样式渲染规则</h3>
<p><strong>规则一：后出现的规则会覆盖先出现的规则（即层叠规则）</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">p</span> <span class="p">{</span> <span class="k">color</span><span class="p">:</span> <span class="kc">red</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nt">p</span> <span class="p">{</span> <span class="k">color</span><span class="p">:</span> <span class="n">blud</span><span class="p">;</span> <span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在同等优先级的情况下 <code>css</code> 后出现的会覆盖之前出现的，可以理解为按顺序声明的语句。</p>
<p><strong>规则二：更具体的选择器具备更高的优先级：</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">.</span><span class="nc">special</span> <span class="p">{</span> <span class="k">color</span><span class="p">:</span> <span class="kc">blue</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nt">p</span> <span class="p">{</span> <span class="k">color</span><span class="p">:</span> <span class="kc">red</span><span class="p">;</span> <span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;special&#34;</span><span class="p">&gt;</span>我是什么颜色的？<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>例如上述 Case 中，css 中 special 的定义是在段落的基础之前的，因此段落文本理论上首先被渲染为蓝色，后续被 p 的红色覆盖，但是由于 special 作为类，被认为是比基础标签 p 的优先级更高，因此最终会被渲染成蓝色；</p>
<p><strong>具体的权重计算规则：</strong></p>
<p>一个选择器的优先级可以说是由三个不同的值（或分量）相加，可以认为是百（ID）十（类）个（元素）——三位数的三个位数：</p>
<ul>
<li><strong>ID</strong>：选择器中包含 ID 选择器则百位得一分。</li>
<li><strong>类</strong>：选择器中包含类选择器、属性选择器或者伪类则十位得一分。</li>
<li><strong>元素</strong>：选择器中包含元素、伪元素选择器则个位得一分。</li>
</ul>
<p>此外还有<strong>内联样式</strong>：总是最高优先级; 以及特殊的属性值  <code>!important</code> 也是默认为<strong>最高优先级</strong></p>
<p>因此，由于优先级的存在，有时候某个元素可能会不按照预期渲染，这种时候查看被多少个选择器选中并进行调整即可。且优先级计算的时，由于有 <code>!important</code> 特殊属性值的存在，因此并不总是按照组来整体应用和计算。<code>@important</code> 和其他的属性不同，是先定义的优先级更高。</p>
<h3 id="样式继承关系">样式继承关系</h3>
<blockquote>
<p>子元素的例如颜色，字体等属性是会继承父元素的，而像是 box 相关的边框属性（边框边距等）是不会继承的，否则设置了一个相对 page 为 50%的 box，其中的子元素直接指数级缩小可还得了。</p>
</blockquote>
<p>🔥<a href="https://youtu.be/Sp9ZfSvpf7A" target="_blank" rel="noopener">mdn YTB 视频教程：如何使用开发者工具来检查级联和优先级</a>
： 在 rule 面板会列出所有的规则，可以点击元素旁边的按钮来定位，也可以直接在页面上修改，且位于越上方的规则其权重越重。在规则页面的下方也会有继承的面板。</p>
<p>当然也可以手动的调整和控制继承，CSS 定义了五个特殊的<strong>通用属性值</strong>，用来简化部分内容重写的工作：</p>
<ul>
<li><code>inherit</code> 继承父元素的对应属性值，实际上就是开启集成</li>
<li><code>initial</code> 将属性还原初始值</li>
<li><code>revert</code> 还原为浏览器的默认样式，大多数情况下=unset</li>
<li><code>revert-layer</code> 将属性值还原为上一个层叠层中建立的值</li>
<li><code>unset</code> 重置为自然值，如果属性是自然继承就是 inherited, 否则就是 initial。</li>
</ul>
<p>可以结合 <code>all</code> 属性将所有属性重置。</p>
<h3 id="级联层顺序">级联层顺序</h3>
<p>级联层相当于是将 css 分成几个大组，同样还是后声明的优先级更高，同样 import 还是个例外是相反的。未包含在某个级联层的则会默认放在最后一个未命名的组中声明，因此会有最高的优先级。</p>
<p>下面给个级联层的定义例子，这个特性暂时不需要掌握，后续再看。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="p">@</span><span class="k">layer</span> <span class="nt">firstLayer</span><span class="o">,</span> <span class="nt">secondLayer</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">p</span> <span class="p">{</span> <span class="c">/* 0-0-1 */</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-color</span><span class="p">:</span> <span class="kc">red</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="kc">grey</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">border</span><span class="p">:</span> <span class="mi">5</span><span class="kt">px</span> <span class="kc">inset</span> <span class="kc">purple</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nt">p</span><span class="p">#</span><span class="nn">addSpecificity</span> <span class="p">{</span> <span class="c">/* 1-0-1 */</span>
</span></span><span class="line"><span class="cl">  <span class="k">border-style</span><span class="p">:</span> <span class="kc">solid</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">@</span><span class="k">layer</span> <span class="nt">firstLayer</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="p">#</span><span class="nn">addSpecificity</span> <span class="p">{</span> <span class="c">/* 1-0-0 */</span>
</span></span><span class="line"><span class="cl">    <span class="k">background-color</span><span class="p">:</span> <span class="kc">blue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">color</span><span class="p">:</span> <span class="kc">white</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">border-width</span><span class="p">:</span> <span class="mi">5</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">border-style</span><span class="p">:</span> <span class="kc">dashed</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">@</span><span class="k">layer</span> <span class="nt">secondLayer</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">p</span><span class="p">#</span><span class="nn">addSpecificity</span> <span class="p">{</span> <span class="c">/* 1-0-1 */</span>
</span></span><span class="line"><span class="cl">    <span class="k">background-color</span><span class="p">:</span> <span class="kc">green</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">color</span><span class="p">:</span> <span class="kc">orange</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">border-width</span><span class="p">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">border-style</span><span class="p">:</span> <span class="kc">dotted</span> <span class="cp">!important</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script>]]></content:encoded>
    </item>
    <item>
      <title>LearnWeb07-HTML04-表格基础</title>
      <link>https://aikenh.cn/posts/learnweb07-html04-%E8%A1%A8%E6%A0%BC%E5%9F%BA%E7%A1%80/</link>
      <pubDate>Sun, 04 Feb 2024 16:30:09 +0000</pubDate>
      <guid>https://aikenh.cn/posts/learnweb07-html04-%E8%A1%A8%E6%A0%BC%E5%9F%BA%E7%A1%80/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-summary&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Summary&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;HTML 中需要使用 CSS 进行样式组合才能得到一个阅读体验较好的表格，目前还是先专注在 HTML 的部分，后面到 CSS 部分的时候再合起来一起看。&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>HTML 中需要使用 CSS 进行样式组合才能得到一个阅读体验较好的表格，目前还是先专注在 HTML 的部分，后面到 CSS 部分的时候再合起来一起看。</p>

</blockquote>
<p>本文主要是参考 <a href="https://mdn.github.io/learning-area/html/tables/basic/personal-pronouns-styled.html" target="_blank" rel="noopener">MDN 范例</a>
中的源码以及对应的文章 <a href="https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Tables/Basics" target="_blank" rel="noopener">HTML 表格基础</a>
的一篇阅读笔记。</p>
<h2 id="表格基础">表格基础</h2>
<p>从源码开始我们可以看到表格对应的 Tag 核心的一下几个：</p>
<ul>
<li><code>&lt;Table&gt;</code> 包裹整个表格</li>
<li><code>&lt;caption&gt;</code> 设置表格的标题</li>
<li><code>&lt;tr&gt;</code> 一行一行的包裹表格，全称应该是 table row</li>
</ul>
<p>可以看到 HTML 中编写表格是使用 <code>&lt;tr&gt;</code> 进行逐行编写的，逐行的描述整个表格：</p>
<ul>
<li>用 <code>&lt;td&gt;</code> 描述表格的内容语义，table data</li>
<li>用 <code>&lt;th&gt;</code> 描述表格的标题语义，即首行首列的标题元素 table header</li>
</ul>
<p>主要的元素就是上面这些，但是复杂的表格包括：合并的单元格（纵向和横向）需要再 <code>th</code> 和 <code>td</code> 中使用额外的属性来定义：<code>colspan</code> 和 <code>rowspan</code></p>
<ul>
<li><code>colspan=&quot;2&quot;</code> 属性定义占据两个单元格宽度（横向合并）</li>
<li><code>rowspan=&quot;3&quot;</code> 属性定义占据三个单元格的宽度（纵向合并）</li>
</ul>
<p>然后每个 tr 中排除掉被合并的单元格还需要多少个 td 需要我们自己计算。</p>
<h3 id="html-的表格基础样式">HTML 的表格基础样式</h3>
<p>可以使用 <code>colgroup</code> 和 <code>col</code> 为整列设置同样的样式，每个 col 元素代表一列，如果需要一条元素定义多列的样式的时候可以使用 span 属性，下述代码会将第二列背景设置为黄色。</p>
<p>对单个单元格设置样式可以仿照使用 style 属性来嵌入对应的 css 样式，包括宽度什么的。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">table</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">colgroup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">col</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">col</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;background-color: yellow&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">colgroup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">tr</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">th</span><span class="p">&gt;</span>Data 1<span class="p">&lt;/</span><span class="nt">th</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">th</span><span class="p">&gt;</span>Data 2<span class="p">&lt;/</span><span class="nt">th</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">tr</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">tr</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">td</span><span class="p">&gt;</span>Calcutta<span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">td</span><span class="p">&gt;</span>Orange<span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">tr</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">tr</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">td</span><span class="p">&gt;</span>Robots<span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">td</span><span class="p">&gt;</span>Jazz<span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">tr</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">table</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="html-表格结构化">HTML 表格结构化</h3>



  
  

<blockquote class="alert-blockquote alert-quota">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Quota</span>
  </p>
  <p>由于表格在结构上有点复杂，如果把它们定义得更加结构化，那会帮助我们更能了解结构。一个明确的方法是使用 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/thead" target="_blank" rel="noopener"><code>&lt;thead&gt;</code></a>
、<a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/tfoot" target="_blank" rel="noopener"><code>&lt;tfoot&gt;</code></a>
 和 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/tbody" target="_blank" rel="noopener"><code>&lt;tbody&gt;</code></a>
，这些元素允许你把表格中的部分标记为表头、表尾、表体三部分。</p>

</blockquote>
<p>这样的结构化实际上没有什么默认 style，主要是帮助我们后续定义各个部分的样式。</p>
<h2 id="其他">其他</h2>
<ul>
<li>表格元素支持嵌套</li>
<li>使用 <a href="https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Tables/Advanced#scope_%E5%B1%9E%E6%80%A7" target="_blank" rel="noopener">scope 属性</a>
 来支持视障人士来理解这个表格</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>LearnWeb06-HTML03-多媒体元素</title>
      <link>https://aikenh.cn/posts/learnweb06-html03-%E5%A4%9A%E5%AA%92%E4%BD%93%E5%85%83%E7%B4%A0/</link>
      <pubDate>Sat, 03 Feb 2024 09:51:08 +0000</pubDate>
      <guid>https://aikenh.cn/posts/learnweb06-html03-%E5%A4%9A%E5%AA%92%E4%BD%93%E5%85%83%E7%B4%A0/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-summary&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Summary&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;接下来主要探讨 HTML 中的多媒体元素，图片、视频、音频以及 iframe 等等。&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>接下来主要探讨 HTML 中的多媒体元素，图片、视频、音频以及 iframe 等等。</p>

</blockquote>
<h2 id="图片元素-image">图片元素 Image</h2>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;&lt;img_url or location&gt;&#34;</span> <span class="p">/&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><code>src </code>：最基本的图片元素仅需一个 <strong>src</strong> 属性来指向图片资源，这样就可以将图片导入页面中，其中关于 Location 这里有一个 SEO Tips(Google Recommand)：</p>
<ul>
<li>本地存储推荐存储于 <code>images</code></li>
<li>图片的命名更加具备描述性。</li>
<li>不要将自己的 SRC 属性指向他人网页上的照片（这种行为为&quot;盗链&quot;）</li>
</ul>
<p>如图像元素和视频元素这类嵌入的元素，有时候也被成为<strong>替换元素</strong>：元素的内容和原始尺寸由外部资源所定义，而非元素本身。（可以使用属性或者 CSS 进行控制）</p>
<p><code>alt</code>：alt 为了视障，节省带宽，浏览器支持问题等原因设置的代替图片出现的描述性文本，推荐根据图片内容进行编写：</p>
<ul>
<li><code>装饰需求 </code>: 使用空的 <code>alt=&quot;&quot;</code> 避免输出多余信息，同时推荐将装饰性图片在 CSS 文件中定义而非 html，下文会详细讲解 CSS 设置装饰图片</li>
<li><code>内容需求</code>：如果正文中没有描述，则 alt 对图片进行描述，否则设置为空。</li>
</ul>
<p><code>width</code> 与 <code>height</code> ：上文中提到图片的 size 由外部资源决定，单位了适应页面的大小，可以使用 img 标签中的 width 和 height 属性来实现对图片的缩放，同时也会<strong>在页面尚未加载完成时预留空间，避免页面结构混乱</strong>。（因此无需缩放也建议，获取图片的 size 写入属性。）</p>
<p><code>title</code>：类似超链接中的 title 属性，可以给照片添加悬停提示，当空间不够时可以通过这种方式来添加部分信息，但不推荐。</p>
<p><code>figure</code> 与 <code>figcaption</code>：创建一个容器（box），可以为图片在图片下方添加说明，像论文中的那种，对于无障碍用户来说起到和 alt 一样的作用。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">figure</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span> <span class="s">&#34;https://the-network-photo&#34;</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;&#34;</span> <span class="na">title</span><span class="o">=</span><span class="s">&#34;key img&#34;</span><span class="err">,</span> <span class="na">width</span><span class="o">=</span><span class="s">&#34;400&#34;</span><span class="err">,</span> <span class="na">height</span><span class="o">=</span><span class="s">&#34;200&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">figcaption</span><span class="p">&gt;</span>通过为网络添加一个低纬嵌入来实现用最小的空间代价控制网路行为<span class="p">&lt;/</span><span class="nt">figcaption</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">figure</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>figure 中可以存放几张图片、一段代码、音视频、方程、或者任何其他的内容，而不只是单张照片，类似的补充说明的场景都可以使用 figure 元素呈现。</p>
<h3 id="使用-css-添加背景图片">使用 CSS 添加背景图片</h3>
<p>举个例子，为整个页面/任何标签/元素设置一个背景图片，可以使用 <code>background-img</code> 属性来指定图片，并使用 <code> background-*</code> 属性来指定图片的 size 等呈现方式。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">html</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="n">background-img</span><span class="p">:</span> <span class="nb">url</span><span class="p">(</span><span class="s2">&#34;images/dinosaur.jpg&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="k">background-size</span><span class="p">:</span> <span class="kc">auto</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="音视频内容-video--audio">音视频内容 Video &amp; Audio</h2>
<blockquote>
<p><strong>补充知识</strong>：早期的 HTML 无法支持音视频因此有了 FLash 等技术的兴起，由于安全性和其无法支持 HTML 和 CSS 特性，且后续 HTML5 中支持了 <code>video</code> 和 <code>audio</code> 标签，故而这些技术就被淘汰。</p>
</blockquote>
<p>音视频的插入方式主要有：</p>
<ul>
<li>（学习）HTML5 提供了 <code>video</code> 和 <code>audio</code> 标签支持以及相应的 JavaScript 中提供了 <a href="https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLMediaElement" target="_blank" rel="noopener"><code>APIs</code></a>
对这些音视频进行控制，</li>
<li>（推荐）OVPs(Online Video Provide Server)在线视频/音频提供商，如 b 站和 youtube 等，会提供现成的代码在网页中嵌入其音视频资源，可以避免我们主机的带宽消耗等诸多难题</li>
</ul>
<h3 id="video-元素">Video 元素</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">video</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;your video location or url&#34;</span> <span class="na">controls</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">		你的浏览器不支持HTML5视频,可点击<span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;videosize&#34;</span><span class="p">&gt;</span>此链接<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>观看
</span></span><span class="line"><span class="cl">	<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">video</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>使用方式和 <code>&lt;img&gt;</code> 标签相似使用 src 定位资源，而其他的一些别的用法说明：</p>
<ul>
<li>controls：布尔属性，为视频包含浏览器提供的默认控件页面来控制视频的播放，同时也可以使用 <a href="https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLMediaElement" target="_blank" rel="noopener">JS Media API</a>
 来创建自己的页面</li>
<li>标签中包裹的内容：如 <code>&lt;img&gt;</code> 中的 <code>alt</code> 为视频提供后备方案，如果视频不被支持或者加载失败，可以显示其中内容。</li>
</ul>
<p>由于浏览器/设备的对不同音视频编解码器的不同支持(相关编解码知识请参考 <a href="https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content#%E4%BD%BF%E7%94%A8%E5%A4%9A%E4%B8%AA%E6%92%AD%E6%94%BE%E6%BA%90%E4%BB%A5%E6%8F%90%E9%AB%98%E5%85%BC%E5%AE%B9%E6%80%A7" target="_blank" rel="noopener">MDN</a>
 使用多个播放源以提高兼容性章节)，可能会需要<strong>提供多个备选资源来源</strong>，可以使用以下的方式：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">video</span> <span class="na">controls</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">source</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;name.mp4&#34;</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;video/mp4&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">source</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;name.webm&#34;</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;video/webm&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">		你的浏览器不支持HTML5视频,可点击<span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;videosize&#34;</span><span class="p">&gt;</span>此链接<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>观看
</span></span><span class="line"><span class="cl">	<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">video</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>还有一些其他的属性，需要的时候建议查看文档。</p>
<ul>
<li><code>width</code> 和 <code>height</code></li>
<li><code>autoplay</code>：自动开始播放；<code>loop</code>：自动循环播放</li>
<li><code>muted</code>：默认静音</li>
<li><code>poster</code>：指向一个图像的 url，通常用于预览或者广告</li>
<li><code>preload</code>：提供缓冲选项，none，auto，metadata 三个选项。</li>
</ul>
<p>可以使用 <code>track</code> 标签，基于 <code>WebVTT</code> 格式为视频提供字幕，具体例子如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">video</span> <span class="na">controls</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">source</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;example.mp4&#34;</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;video/mp4&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">source</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;example.webm&#34;</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;video/webm&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">track</span> <span class="na">kind</span><span class="o">=</span><span class="s">&#34;subtitles&#34;</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;subtitles_en.vtt&#34;</span> <span class="na">srclang</span><span class="o">=</span><span class="s">&#34;en&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">video</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>其中 king 中有 subtitle 翻译字幕，caption 同步字幕，timed description 将文字转换为音频，服务视觉障碍人士。</p>
<h3 id="audio-元素">audio 元素</h3>
<p>音频元素和视频元素基本完全一致，区别由于占用的空间较小，因此没有视觉部件，如同 <code>width</code>, <code>height</code> 和 <code>poster</code></p>
<h3 id="js-控制举例">JS 控制举例</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">mediaElem</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">&#34;my-media-element&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">mediaElem</span><span class="p">.</span><span class="nx">load</span><span class="p">();</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>例如：使用上述 load 命令可以重置媒体元素，其他的控制等使用的时候再进行补充</p>
<h2 id="网页与其他对象的嵌入-iframeobject">网页与其他对象的嵌入 Iframe&amp;Object</h2>
<p>可以上 Mdn 查看 Web 中各种<a href="https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies" target="_blank" rel="noopener">嵌入元素的简史</a>
，这里主要记录 <code>iframe</code> 元素：提供了一种将整个 web 页面嵌入另一个网页中的方法，是现在 web 中经常被使用的元素。</p>
<blockquote>
<p>上文中提到的基于 OVPs 插入音视频的方法实际上就是基于 iframe 元素实现的，通常可以在 OVPs 页面的分享处找到，复制其嵌入代码即可。</p>
</blockquote>
<p>随便找了一个 B 站的例子，使用 <code>&lt;iframe&gt;</code> tag，以 src 指定嵌入来源，还有其他相关的诸多属性设置。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">iframe</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;//player.bilibili.com/player.html?aid=1750103776&amp;bvid=BV1m4421w7a2&amp;cid=1428891154&amp;p=1&#34;</span> <span class="na">scrolling</span><span class="o">=</span><span class="s">&#34;no&#34;</span> <span class="na">border</span><span class="o">=</span><span class="s">&#34;0&#34;</span> <span class="na">frameborder</span><span class="o">=</span><span class="s">&#34;no&#34;</span> <span class="na">framespacing</span><span class="o">=</span><span class="s">&#34;0&#34;</span> <span class="na">allowfullscreen</span><span class="o">=</span><span class="s">&#34;true&#34;</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">iframe</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>除了视频还可以嵌入：在线地图、广告、Disqus 评论系统等，接下来可以介绍一下一些常用的属性。</p>
<ul>
<li><code>width=“100%“</code> 与 <code>height=&quot;500&quot;</code> 支持百分比和像素控制两种，可以指定一个绝对值剩下百分比。</li>
<li><code>frameborder</code>: 设置为 1 会绘制边框，0 会删除边框，建议设置为 0，不建议设置，可以在 css 中操作边框的表现，如 <code>border: none;</code></li>
<li><code>allowfullscreen</code>：布尔属性，是否可以以全屏方式打开该 frame。</li>
<li><code>sandbox</code>：<strong>无脑 100%添加</strong>，可以增加一些安全性，但是需要较新的浏览器版本。</li>
</ul>
<p><code>&lt;iframe&gt;</code> 可以如视频一样指定备选内容，如果无法加载的话就显示对应的备选内容，或者直接指向视频网站。</p>
<h3 id="废弃-embed--object-嵌入">废弃 embed &amp; object 嵌入</h3>
<p>这两个 Tag 可以嵌入 Flash，脚本和 PDF 等内容，但是并不推荐这么去做，详细请参考 <a href="https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies" target="_blank" rel="noopener">MDN 说明</a>
，避免使用 Flash 这个过时的技术，像 PDF 这种最好直接指向其链接，而非将其添加为嵌入。</p>
<h3 id="部分安全设置">部分安全设置</h3>
<ol>
<li><strong>CSP 指令</strong>：部署网站的时候添加安全响应头，避免自己的网站被别人作为嵌入插入自己的页面，为自己带来没有必要的额外带宽消耗。</li>
</ol>
<p>方法参考自 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/X-Frame-Options" target="_blank" rel="noopener">MDN</a>
，配置 Nginx，将一下这行添加到 http,server,或者 location 的配置中。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>conf</span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code class="language-conf" data-lang="conf">add_header X-Frame-Options SAMEORIGIN always;</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="2">
<li>使用HTTPS</li>
</ol>
<h2 id="矢量图形-svg">矢量图形 SVG</h2>
<p>矢量图的定义这里不再重复，其用一组函数来定义图形，具体的编写方法这里也不再多说，最好使用第三方工具直接生成 SVG。这里只介绍一下如何插入和操作 SVG：</p>
<p>插入 SVG 主要有两种方法：</p>
<ul>
<li>第一种可以使用 <code>&lt;img&gt;</code> 但是无法使用 JS 操作图像，且只有在 svg 内部的 css 才能操作其样式</li>
<li>第二种直接使用 <code>&lt;svg&gt;</code> 里面添加 svg 的定义代码，可以为其添加 class 和 id，可以使用外部 css 调整器样式</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">svg</span> <span class="na">width</span><span class="o">=</span><span class="s">&#34;300&#34;</span> <span class="na">height</span><span class="o">=</span><span class="s">&#34;200&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">rect</span> <span class="na">width</span><span class="o">=</span><span class="s">&#34;100%&#34;</span> <span class="na">height</span><span class="o">=</span><span class="s">&#34;100%&#34;</span> <span class="na">fill</span><span class="o">=</span><span class="s">&#34;green&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">svg</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>想要了解 SVG 还是从 <a href="https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web" target="_blank" rel="noopener">MDN 原文</a>
开始并补充更多绘图知识吧。</p>
<h2 id="响应式图片">🔥响应式图片</h2>
<p><strong>响应式照片</strong>：如何在<strong>不同的屏幕尺寸，分辨率设备</strong>上都显示良好的图片，从而提升阅读体验和性能，之所以在 HTML 就需要介绍响应式图片，是因为页面在刚开始加载的时候就会获取图片，会先于 JS 和 CSS 显示出来，等到 JS 检测再动态加载新的照片会有点缓慢/奇怪。</p>



  
  

<blockquote class="alert-blockquote alert-note">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Note</span>
  </p>
  <p>CSS 是比 HTML 更好的响应式设计工具，本章节仅仅专注于 HTML，待到 CSS 部分再学习。</p>

</blockquote>



  
  

<blockquote class="alert-blockquote alert-todo">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Todo</span>
  </p>
  <p>该部分肯定还要再深入研究的，这一点肯定不够用。</p>

</blockquote>
<h3 id="针对不同分辨率提供不同尺寸的图片">针对不同分辨率提供不同尺寸的图片</h3>
<p>使用 img 中额外的属性 <code>scrset</code> 和 <code>sizes</code> 来指定不同条件下是选择显示的照片如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">img</span>
</span></span><span class="line"><span class="cl">  <span class="na">srcset</span><span class="o">=</span><span class="s">&#34;elva-fairy-480w.jpg 480w, elva-fairy-800w.jpg 800w&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">sizes</span><span class="o">=</span><span class="s">&#34;(max-width: 600px) 480px,
</span></span></span><span class="line"><span class="cl"><span class="s">         800px&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">src</span><span class="o">=</span><span class="s">&#34;elva-fairy-800w.jpg&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">alt</span><span class="o">=</span><span class="s">&#34;Elva dressed as a fairy&#34;</span> <span class="p">/&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li><code>srcset</code> 使用 <code>, </code> 分割多个图片 src</li>
<li><code>sizes</code> 使用类似三元表达式的形式做判断，<code>(cond), res1, res2</code> 例如这里 cond 为屏幕宽度&lt;=600px，这样在小分辨率屏幕下就会选择原始尺寸更接近 480px 的图片（res1，res2 需要取图片的固有宽度曲线则）进行渲染。</li>
</ul>
<p><code>html</code> 文件的 <code>head</code> 中的 <code>&lt;meta name=&quot;viewport&quot; content=&quot;width-device-width&quot;&gt;</code> 会强制让手机浏览器采用他们的真实可视窗口的宽度来加载网页，这样避免错误的尺寸（有的浏览器会虚报放大再缩小）为网页响应式渲染带来问题。</p>
<p>这种情况下，图片的大小在不同分辨率的屏幕上是不同的，取决于照片本身。</p>
<h3 id="为不同分辨率提供相同尺寸的图片">为不同分辨率提供相同尺寸的图片</h3>
<p>希望在不同分辨率屏幕上看到的实际尺寸是相同的，可以使用 <code>srcset</code> 结合 x 语法来让浏览器选择合适的照片。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">img</span>
</span></span><span class="line"><span class="cl">  <span class="na">srcset</span><span class="o">=</span><span class="s">&#34;elva-fairy-320w.jpg, elva-fairy-480w.jpg 1.5x, elva-fairy-640w.jpg 2x&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">src</span><span class="o">=</span><span class="s">&#34;elva-fairy-640w.jpg&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">alt</span><span class="o">=</span><span class="s">&#34;Elva dressed as a fairy&#34;</span> <span class="p">/&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在这种情况下，会计算屏幕用多少个像素表示一个 css 像素，也就是说按照分辨率与标准分辨率的倍数来选择/缩放照片。</p>
<h3 id="美术设计更为实际的需求">美术设计（更为实际的需求）</h3>
<p>同一张照片在手机上表示效果如果和桌面端保持一致，可能会导致图片中的元素过小等各种各样的问题，导致阅读起来非常不便，这里建议使用 <code>&lt;picture&gt;</code> 属性替换 img 属性。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">picture</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">source</span> <span class="na">media</span><span class="o">=</span><span class="s">&#34;(max-width: 799px)&#34;</span> <span class="na">srcset</span><span class="o">=</span><span class="s">&#34;elva-480w-close-portrait.jpg&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">source</span> <span class="na">media</span><span class="o">=</span><span class="s">&#34;(min-width: 800px)&#34;</span> <span class="na">srcset</span><span class="o">=</span><span class="s">&#34;elva-800w.jpg&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;elva-800w.jpg&#34;</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;Chris standing up holding his daughter Elva&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">picture</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>同样在 media 选择条件，scrset 设置将会加载的图像。这种情况下我们<strong>可以对多张照片分别指定 size</strong>，来满足更为灵活的多样定制英雄，切记里面至少要有一个默认图像元素 <code>img</code>。</p>
<h3 id="使用新图像格式">使用新图像格式</h3>
<p><code>WebP</code> 和 <code>AVIF</code> 都可以在高质量的时候保持较小的文件大小。</p>
<h2 id="总结-fi">总结 FI</h2>
<ul>
<li>音视频方面：建议还是尽量使用视频提供商来嵌入多媒体内容，这些方式带来的带宽消耗和各种问题都相对棘手。</li>
<li>网页部署的时候需要注意 iframe 安全，同时可以使用 iframe 嵌入有趣的内容，但是切记仅在必要的时候嵌入</li>
<li>SVG 相比 img 有诸多优势，但是最好还是使用第三方软件生成。</li>
<li>使用响应式图片来适应多种屏幕，不打算使用美术设计的时候不要用 media 属性。</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>LearnWeb05-HTML02-要素察觉</title>
      <link>https://aikenh.cn/posts/learnweb05-html02-%E8%A6%81%E7%B4%A0%E5%AF%9F%E8%A7%89/</link>
      <pubDate>Fri, 02 Feb 2024 14:09:15 +0000</pubDate>
      <guid>https://aikenh.cn/posts/learnweb05-html02-%E8%A6%81%E7%B4%A0%E5%AF%9F%E8%A7%89/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-summary&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Summary&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;本章节在 HTML01 的基础上加深对于一些基础概念，标签等的认知，还是以 HTML 编写的基础知识为主。&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>本章节在 HTML01 的基础上加深对于一些基础概念，标签等的认知，还是以 HTML 编写的基础知识为主。</p>

</blockquote>
<h2 id="块级元素和内联元素">块级元素和内联元素</h2>
<p>块级元素和内联元素就像 Markdown 的内联代码和代码块两种写法，一个需要另起一行且会占据行，下一个元素必须另起一行，如 <code>&lt;p&gt;</code> 段落等。而内联元素就是可以嵌入行内，内联元素前后都无需换行，一般如强调，高亮，超链接一类。</p>
<ul>
<li>正是由于这种结构，<strong>块级元素</strong>在使用的时候除了内容，往往还承担着<strong>网页的结构</strong>相关的工作，如页眉，页脚, 列表，导航栏等等；</li>
<li><strong>块级元素</strong>不会嵌套在内联元素中，但是可能嵌套在另一个块级元素中。</li>
<li><strong>内联元素</strong>则通常在块级元素中和文本一起使用。</li>
</ul>
<blockquote>
<p>需要注意的是这类元素分类是过时的，HTML 定义了更加详细具体的分类，为了便于理解暂时使用旧的定义来做简单的区分。</p>
</blockquote>
<h2 id="布尔属性">布尔属性</h2>
<p>前文提到过，属性通常以 k-v 键值对的形式呈现，但是有部分属性是没有值的，其 key 通常与值有着相同的含义，如 <code>disabled</code>，该布尔属性本身就代表着禁用，例如输入框 <code>&lt;input&gt;</code> 禁用就会阻止用户的输入。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">disabled</span> <span class="p">/&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这样就会创建一个无法输入的输入框，通常会以灰色呈现，type 则限制了输入框的输入类型。</p>
<h2 id="html-头部">HTML 头部</h2>
<p>html01 中已经简单介绍过一些在 HTML Head 中的元素，这里主要为其中的元素添加更为详细的说明</p>
<h3 id="添加页面图标">添加页面图标</h3>
<p>页面添加网页图标的方式有：</p>
<ol>
<li>将其保存在与网站的索引页面相同的目录中，以 <code>.ico</code> 格式保存（大多数浏览器支持更通用的格式，如 <code>.gif</code> 或 <code>.png</code>）</li>
<li>将以下行添加到 HTML 的 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/head" target="_blank" rel="noopener"><code>&lt;head&gt;</code></a>
 块中以引用它，可能会看到很多其他针对不同设备保存不同图标的代码，也会用类似的语句写在这里。</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;icon&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;favicon.ico&#34;</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;image/x-icon&#34;</span> <span class="p">/&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="设置主语言">设置主语言</h3>
<p>例如在 <code>&lt;html lang='zh-CN'&gt;</code> HTMl 标签中加入 lang 属性为整个页面设置中文标签，这是为了搜索引擎的&quot;搜索特定语言的页面&quot;等功能提供支持。</p>
<p>也可以分段添加语言信息（可能为了视障人士设计，阅读时候切换语言）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>Japanese example: <span class="p">&lt;</span><span class="nt">span</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;ja&#34;</span><span class="p">&gt;</span>ご飯が熱い。<span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>.<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="meta-元数据">Meta 元数据</h3>
<p>元数据就是描述数据的数据，实际上所有在 Head 部分的数据都能称之为元数据，包括 JS，CSS 引用等等。而 HTML 有一个“官方的”方式来为一个文档添加元数据—— <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/meta" target="_blank" rel="noopener"><code>&lt;meta&gt;</code></a>
 元素。用来指定网页编码的如下代码就是使用的 meta tag</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;utf-8&#34;</span> <span class="p">/&gt;</span> </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>正确的使用需要的编码能避免渲染时出现乱码，Meta 除了设置字符编码的元数据，还有以下的其他用法，大多是用于各个网站的专有元数据：</p>
<p>Meta 标签中包含的<strong>name</strong>和<strong>content</strong>属性，分别对应元素的说明，和元素的具体的值，可用来添加作者信息，详细描述，联系方式等额外信息，这些字段有如下的用处：</p>
<ul>
<li>用于爬虫或者一些<strong>自动化处理</strong>的工作</li>
<li><strong>SEO 优化</strong>，使得网页在搜索引擎上出现的更多，例如 <code>description</code> 中的信息也会被搜索引擎用于搜索结果。</li>
</ul>
<blockquote>
<p>在谷歌搜索里，在主页面链接下面，你将看到一些相关子页面——这些是站点链接，可以在 <a href="https://search.google.com/search-console/about" target="_blank" rel="noopener">Google&rsquo;s webmaster tools</a>
 配置——这是一种可以使你的站点对搜索引擎更友好的方式。</p>
</blockquote>
<blockquote>
<p>许多 <code>&lt;meta&gt;</code> 特性已经不再使用。例如，keyword <code>&lt;meta&gt;</code> 元素（<code>&lt;meta name=&quot;keywords&quot; content=&quot;fill, in, your, keywords, here&quot;&gt;</code>，为搜索引擎提供关键词，用于确定该页面与不同搜索词的相关性）已经被搜索引擎忽略了，因为作弊者填充了大量关键词到 keyword，错误地引导搜索结果。</p>
</blockquote>
<p>不同的网站（如 Facebook 之类的社交平台），涉及到网站分享，可能会有一些特有的元信息协议，让我们的网站可以为其提供更多额外的信息，如 logo 之类的，在分享的时候就能呈现出来。</p>
<h2 id="body-主体">BODY 主体</h2>
<h3 id="无语义标签">无语义标签</h3>
<p>除了 HTML01 中介绍的一些涵盖语义的标签（如 h1 等标题语义可能会在 web 的各种延伸应用中被使用，如阅读或搜索），还有一些不含语义的元素如</p>
<ul>
<li>块级的 <code>&lt;div&gt;</code></li>
<li>内联级的 <code>&lt;span&gt;</code></li>
</ul>
<p>这些元素是为了标记部分内容，便于开发者对其实现样式或者动态规则等的设置出现的，举个例子</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">span</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;font-size: 32px; margin: 21px 0; display: block;&#34;</span><span class="p">&gt;</span>这是顶级标题吗？<span class="p">&lt;/</span><span class="nt">span</span>
</span></span><span class="line"><span class="cl"><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>span 没有含义和任何样式，该标签可以提供 class,id 等属性，使其可以用 css（如果是统一格式最好使用外嵌 css 文件的方式）进行控制。</p>
<blockquote>
<p>The <code>&lt;span&gt;</code> element is a very generic inline container that doesn&rsquo;t inherently represent anything. It can be easily styled with CSS or manipulated with JavaScript, making it a versatile tool for web developers to create specific styles or behaviors on parts of their content.【CHATGPT】</p>
</blockquote>
<p>这些元素最好在找不到合适的语义描述的时候再进行使用，避免滥用导致代码可读性降低。</p>
<h3 id="em--strong-强调">em &amp; Strong 强调</h3>
<ul>
<li><code>&lt;strong&gt;</code> 强烈（语义），显示未粗体，如果只是为了展现斜体而非强调，建议使用 span 和 css 样式，或者 <code>&lt;b&gt;</code>，不要使用该含语义的标签。</li>
<li><code>&lt;em&gt;</code> 强调（语义），显示为斜体，如果只是为了展现斜体而非强调，建议使用 span 和 css 样式，不要使用该含语义的标签。</li>
</ul>
<h3 id="a-超链接">a 超链接</h3>
<p>基础用法这里不再过多描述，下面给出一个简单的例子，然后就补充一些详细的描述。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#39;https://www.google.com&#39;</span><span class="p">&gt;</span>google<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>超链接可以包裹几乎一切其他的 tag，图片的也行</p>
<ul>
<li>除了 href 属性，还可以使用 <code>target=&quot;_blank&quot;</code> 属性使得页面在新标签页中打开，</li>
<li>使用 title 属性，添加即将跳转的页面的提示信息，悬停提示。</li>
<li>使用 download 属性，为下载链接下载的文件提供默认名称。</li>
<li>电子邮件地址可以在 href 中写为 <code>href=mailto:youremail@mail.com</code> 的话，打开的邮件会自动填充收件人</li>
</ul>
<p>除了跳转链接还可以跳转到文档的特定部分，但是这要求给文档的各个部分添加 <code>id</code> 属性用于标识，一般用于标题 <code>hn</code></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">h2</span> <span class="na">id</span><span class="o">=</span><span class="s">&#39;h2&#39;</span><span class="p">&gt;</span>Title2<span class="p">&lt;/</span><span class="nt">h2</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">参见<span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;some.html#h2&#34;</span><span class="p">&gt;</span>第二章<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>的内容</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果是同个文件的话文件路径/文件名可以省略，在 <code>#</code> 后面添加对应 id 即可。</p>
<h3 id="dl-描述列表">dl 描述列表</h3>
<p>描述列表对应的是一种独特的列表，其主要用于一些类似术语说明的场景，用来标注一组：术语&amp;释义或者问题&amp;答案。其基本使用方式为 <code>&lt;dl&gt;</code> description list 包裹整个组，列表中的每一项术语/问题用 <code>&lt;dt&gt;</code> description term 标记，回答/释义用 <code>&lt;dd&gt;</code> description definition 包裹，下面给出一个例子：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">dl</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">dt</span><span class="p">&gt;</span>谁是电影奥本海默的导演<span class="p">&lt;/</span><span class="nt">dt</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">dd</span><span class="p">&gt;</span>诺兰<span class="p">&lt;/</span><span class="nt">dd</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">dt</span><span class="p">&gt;</span>奥本海默的男主角扮演的角色是什么职业<span class="p">&lt;/</span><span class="nt">dt</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">dd</span><span class="p">&gt;</span>物理学家<span class="p">&lt;/</span><span class="nt">dd</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">dl</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="blockquota-引用块和行内引用">blockquota 引用块和行内引用</h3>
<ul>
<li>块级内容的引用使用 <code>&lt;blockquota&gt;</code> 包裹，里面使用 <code>&lt;cite&gt;</code> 属性来描述引用的地方（实际上 cite 属性在大多数浏览器等地方都没有很好的利用，如果要显示要自己编写）</li>
<li>行内引用使用 <code>&lt;q&gt;</code> 包裹对应的部分，同样建议添加 <code>&lt;cite&gt;</code> 属性。</li>
</ul>
<h3 id="code-代码块">Code 代码块</h3>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/code" target="_blank" rel="noopener"><code>&lt;code&gt;</code></a>
：用于标记计算机通用代码。</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/pre" target="_blank" rel="noopener"><code>&lt;pre&gt;</code></a>
：用于保留空白字符（通常用于代码块）——如果文本中使用了缩进或多余的空白，浏览器将忽略它，你将不会在呈现的页面上看到它。但是，如果你将文本包含在 <code>&lt;pre&gt;&lt;/pre&gt;</code> 标签中，那么空白将会以与你在文本编辑器中看到的相同的方式渲染出来。</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/var" target="_blank" rel="noopener"><code>&lt;var&gt;</code></a>
：用于标记具体变量名。</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/kbd" target="_blank" rel="noopener"><code>&lt;kbd&gt;</code></a>
：用于标记输入电脑的键盘（或其他类型）输入。</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/samp" target="_blank" rel="noopener"><code>&lt;samp&gt;</code></a>
：用于标记计算机程序的输出</li>
</ul>
<p>主要的应该就是 pre 和 code 标记代码块内容，然后在正文编写的时候可以使用 var 标记变量。后面额外的这些标签主要应该是为了方便代码渲染，包括输入输出的区分等。</p>
<h3 id="其他">其他</h3>
<ul>
<li><code>&lt;abbr title=&quot;全名&quot;&gt;</code> 来包裹一个缩写，使得鼠标浮动的时候显示全称</li>
<li><code>&lt;address&gt;</code> 标记联系方式，不知道有啥用</li>
<li><code>&lt;sup&gt;</code> 上标，<code>&lt;sub&gt;</code> 下标</li>
<li><code>&lt;time datetime=&quot;2024-02-02&quot;&gt;</code> 2024 年 2 月 2 日 <code>&lt;/time&gt;</code> 标记时间，主要是为了给计算机或者脚本提供一个更好解析的时间，避免很多不同种类的时间描述带来处理上的麻烦。</li>
<li><code>&lt;br&gt;</code> 提供换行</li>
<li><code>&lt;hr&gt;</code> 提供分割线</li>
</ul>
<h2 id="layout-页面布局">Layout 页面布局</h2>
<blockquote>
<p>对 HTML 这些元素的合理应用能够从 HTML 就很好的&quot;描述&quot;整个页面的布局，也会给视障用户带来便利。为其清楚的了解页面的布局。</p>
</blockquote>
<p>一个标注的页面通常包含以下的元素：（该部分直接摘录自 <a href="https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Introduction_to_HTML/Document_and_website_structure" target="_blank" rel="noopener">MDN</a>
），对应的 html 标记元素</p>
<p><a href="https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Introduction_to_HTML/Document_and_website_structure#%E9%A1%B5%E7%9C%89" target="_blank" rel="noopener">页眉 <code>&lt;header&gt;</code></a>
：通常横跨于整个页面顶部有一个大标题和/或一个标志。这是网站的主要一般信息，通常存在于所有网页。</p>
<p><a href="https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Introduction_to_HTML/Document_and_website_structure#%E5%AF%BC%E8%88%AA%E6%A0%8F" target="_blank" rel="noopener">导航栏 <code>&lt;nav&gt;</code></a>
：指向网站各个主要区段的超链接。通常用菜单按钮、链接或标签页表示。类似于标题栏，导航栏通常应在所有网页之间保持一致，否则会让用户感到疑惑，甚至无所适从。许多 web 设计人员认为导航栏是标题栏的一部分，而不是独立的组件，但这并非绝对；还有人认为，两者独立可以提供更好的 <a href="https://developer.mozilla.org/zh-CN/docs/Learn/Accessibility" target="_blank" rel="noopener">无障碍访问特性</a>
，因为屏幕阅读器可以更清晰地分辨二者。</p>
<p><a href="https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Introduction_to_HTML/Document_and_website_structure#%E4%B8%BB%E5%86%85%E5%AE%B9" target="_blank" rel="noopener">主内容 <code>&lt;main&gt;</code></a>
：中心的大部分区域是当前网页大多数的独有内容，例如视频、文章、地图、新闻等。这些内容是网站的一部分，且会因页面而异。</p>
<p><a href="https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Introduction_to_HTML/Document_and_website_structure#%E4%BE%A7%E8%BE%B9%E6%A0%8F" target="_blank" rel="noopener">侧边栏 <code>&lt;aside&gt;</code></a>
：一些外围信息、链接、引用、广告等。通常与主内容相关（例如一个新闻页面上，侧边栏可能包含作者信息或相关文章链接），还可能存在其他的重复元素，如辅助导航系统。</p>
<p><a href="https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Introduction_to_HTML/Document_and_website_structure#%E9%A1%B5%E8%84%9A" target="_blank" rel="noopener">页脚 <code>&lt;footer&gt;</code></a>
：横跨页面底部的狭长区域。和标题一样，页脚是放置公共信息（比如版权声明或联系方式）的，一般使用较小字体，且通常为次要内容。还可以通过提供快速访问链接来进行 <a href="https://developer.mozilla.org/zh-CN/docs/Glossary/SEO" target="_blank" rel="noopener">SEO</a>
。</p>
<p>针对上述这些标签，有以下的一些其他说明</p>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/main" target="_blank" rel="noopener"><code>&lt;main&gt;</code></a>
：主内容。主内容中还可以有各种子内容区段，可用<a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/article" target="_blank" rel="noopener"><code>&lt;article&gt;</code></a>
、<a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/section" target="_blank" rel="noopener"><code>&lt;section&gt;</code></a>
 和 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/div" target="_blank" rel="noopener"><code>&lt;div&gt;</code></a>
 等元素表示。</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/aside" target="_blank" rel="noopener"><code>&lt;aside&gt;</code></a>
：侧边栏，经常嵌套在 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/main" target="_blank" rel="noopener"><code>&lt;main&gt;</code></a>
 中。</li>
</ul>
<p>理解所有 HTML 区段元素具体含义是很有益处的，这一点将随着个人 web 开发经验的逐渐丰富日趋显现。更多细节请查阅 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element" target="_blank" rel="noopener">HTML 元素参考</a>
。现在，你只需要理解以下主要元素的意义：</p>
<ul>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/main" target="_blank" rel="noopener"><code>&lt;main&gt;</code></a>
 存放每个页面独有的内容。每个页面上只能用一次 <code>&lt;main&gt;</code>，且直接位于 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/body" target="_blank" rel="noopener"><code>&lt;body&gt;</code></a>
 中。最好不要把它嵌套进其他元素。</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/article" target="_blank" rel="noopener"><code>&lt;article&gt;</code></a>
 包围的内容即一篇文章，与页面其他部分无关（比如一篇博文）。</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/section" target="_blank" rel="noopener"><code>&lt;section&gt;</code></a>
 与 <code>&lt;article&gt;</code> 类似，但 <code>&lt;section&gt;</code> 更适用于组织页面使其按功能（比如迷你地图、一组文章标题和摘要）分块。一般的最佳用法是：以 <a href="https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Howto/Set_up_a_proper_title_hierarchy" target="_blank" rel="noopener">标题</a>
 作为开头；也可以把一篇 <code>&lt;article&gt;</code> 分成若干部分并分别置于不同的 <code>&lt;section&gt;</code> 中，也可以把一个区段 <code>&lt;section&gt;</code> 分成若干部分并分别置于不同的 <code>&lt;article&gt;</code> 中，取决于上下文。</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/aside" target="_blank" rel="noopener"><code>&lt;aside&gt;</code></a>
 包含一些间接信息（术语条目、作者简介、相关链接，等等）。</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/header" target="_blank" rel="noopener"><code>&lt;header&gt;</code></a>
 是简介形式的内容。如果它是 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/body" target="_blank" rel="noopener"><code>&lt;body&gt;</code></a>
 的子元素，那么就是网站的全局页眉。如果它是 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/article" target="_blank" rel="noopener"><code>&lt;article&gt;</code></a>
 或<a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/section" target="_blank" rel="noopener"><code>&lt;section&gt;</code></a>
 的子元素，那么它是这些部分特有的页眉（此 <code>&lt;header&gt;</code> 非彼 <a href="https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML#%e5%a2%9e%e5%8a%a0%e4%b8%80%e4%b8%aa%e6%a0%87%e9%a2%98" target="_blank" rel="noopener">标题</a>
）。</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/nav" target="_blank" rel="noopener"><code>&lt;nav&gt;</code></a>
 包含页面主导航功能。其中不应包含二级链接等内容。</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/footer" target="_blank" rel="noopener"><code>&lt;footer&gt;</code></a>
 包含了页面的页脚部分。</li>
</ul>
<h3 id="example-举个例子">Example 举个例子</h3>
<blockquote>
<p>例子来自 MDN 官网的作业，按照这种结构结合 css 去划分各个区块。</p>
</blockquote>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240203094414.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240203094414.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240203094414.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>css 可以上<a href="https://roy-tian.github.io/learning-area/html/introduction-to-html/structuring-a-page-of-content-finished/" target="_blank" rel="noopener">示例网站</a>
按 F12 查看</p>
<h2 id="extra-额外信息">Extra 额外信息</h2>
<h3 id="注释">注释</h3>
<p>HTML 中的注释需要使用如下的方式实现注释： <code>&lt;!--注释的内容--&gt;</code></p>
<h3 id="特殊字符转义">特殊字符&quot;转义&quot;</h3>
<p>我们必须使用字符引用——表示字符的特殊编码，它们可以在那些情况下使用。每个字符引用以符号 &amp; 开始，以分号（;）结束。</p>
<table>
  <thead>
      <tr>
          <th>原义字符</th>
          <th>等价字符引用</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>&lt;</td>
          <td><code>&amp;lt;</code></td>
      </tr>
      <tr>
          <td>&gt;</td>
          <td><code>&amp;gt;</code></td>
      </tr>
      <tr>
          <td>&quot;</td>
          <td><code>&amp;quot;</code></td>
      </tr>
      <tr>
          <td>'</td>
          <td><code>&amp;apos;</code></td>
      </tr>
      <tr>
          <td>&amp;</td>
          <td><code>&amp;amp;</code></td>
      </tr>
  </tbody>
</table>
<p>等价字符引用可以很容易记住，因为它使用的文本可以被看作是小于“&lt;”，引号是“&quot;”，其他的也是如此。要找到更多关于实体引用的信息，请参见 <a href="https://zh.wikipedia.org/wiki/XML%E4%B8%8EHTML%E5%AD%97%E7%AC%A6%E5%AE%9E%E4%BD%93%E5%BC%95%E7%94%A8%E5%88%97%E8%A1%A8" target="_blank" rel="noopener">XML 和 HTML 字符实体引用列表</a>
（维基百科）</p>
<h3 id="页面调试和校验">页面调试和校验</h3>
<p>除了使用 VsCode 和浏览器预览做调试，还可以将 html 的代码放到 <a href="https://validator.w3.org/" target="_blank" rel="noopener">Makeup Validation Service</a>
 做校验。</p>
]]></content:encoded>
    </item>
    <item>
      <title>LearnWeb04-JS01-基础webJS编写</title>
      <link>https://aikenh.cn/posts/learnweb04-js01-%E5%9F%BA%E7%A1%80webjs%E7%BC%96%E5%86%99/</link>
      <pubDate>Wed, 31 Jan 2024 21:42:46 +0000</pubDate>
      <guid>https://aikenh.cn/posts/learnweb04-js01-%E5%9F%BA%E7%A1%80webjs%E7%BC%96%E5%86%99/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-summary&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Summary&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;JS 除了 WEB 在现代还有很多 NodeJS 的应用也会使用 JS，这里只介绍 web 相关的 JS 代码编写的部分。&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>JS 除了 WEB 在现代还有很多 NodeJS 的应用也会使用 JS，这里只介绍 web 相关的 JS 代码编写的部分。</p>

</blockquote>
<p><strong>ref:</strong> <a href="https://developer.mozilla.org/zh-CN/docs/Learn/Getting_started_with_the_web/JavaScript_basics" target="_blank" rel="noopener">mdn JS 快速入门</a>
 | 《数据结构与算法 JavaScript 描述》</p>
<h2 id="intro">Intro</h2>
<p>JavaSript 和 Python 一样是一个脚本编程语言，也均为解释型语言，具备一个编程语言的所有基本编程特性，而在使用 JS 来实现网页的动态特性的时候，主要使用的是以下的一些<strong>特性</strong>：</p>
<blockquote>
<p>解释型语言执行无需<strong>预先编译</strong>为二进制机器码执行，通常 JS 的转换器会使用即时编译的技术来使得代码运行更快。</p>
</blockquote>
<ul>
<li>存储长期/短期信息</li>
<li>文本和 dom 元素操作（使用 js 的 web api 进行操作）</li>
<li>创建监听事件，动态执行对应的函数, 基于时间去搭建动态的网页效果</li>
</ul>
<p>作为一门完备的动态编程语言，可以借由诸多开发者编写的大量工具，为网站提供动态交互的特性（结合浏览器应用程序接口 API）主要用到的包括：</p>
<ul>
<li><strong>浏览器应用程序接口（API）</strong>：浏览器内置的 API 提供了丰富的功能，比如：动态创建 HTML 和设置 CSS 样式、从用户的摄像头采集处理视频流、生成 3D 图像与音频样本等等。</li>
<li><strong>第三方 API</strong>：让开发者可以在自己的站点中整合其他内容提供者（Twitter、Facebook 等）提供的功能。</li>
<li><strong>第三方框架和库</strong>：用来快速构建网站和应用。</li>
</ul>
<table>
  <thead>
      <tr>
          <th style="text-align: center">API 类别</th>
          <th>A</th>
          <th>B</th>
          <th>C</th>
          <th>D</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: center">浏览器API</td>
          <td><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Document_Object_Model" target="_blank" rel="noopener">DOM操作</a>
</td>
          <td><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Geolocation" target="_blank" rel="noopener">地理位置</a>
</td>
          <td><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API" target="_blank" rel="noopener">Canvas</a>
</td>
          <td><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/WebGL_API" target="_blank" rel="noopener">WebGL</a>
 | <a href="https://experiments.withgoogle.com/collection/chrome" target="_blank" rel="noopener">WebGL example</a>
</td>
      </tr>
      <tr>
          <td style="text-align: center"></td>
          <td></td>
          <td></td>
          <td></td>
          <td><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/WebRTC_API" target="_blank" rel="noopener">WebRTC 等影音类API</a>
</td>
      </tr>
      <tr>
          <td style="text-align: center">第三方API</td>
          <td><a href="https://developer.twitter.com/en/docs" target="_blank" rel="noopener">Twitter</a>
</td>
          <td><a href="https://open.weibo.com/" target="_blank" rel="noopener">新浪微博</a>
</td>
          <td><a href="https://developers.google.com/maps/" target="_blank" rel="noopener">谷歌地图</a>
</td>
          <td><a href="https://lbs.amap.com/" target="_blank" rel="noopener">高德地图</a>
</td>
      </tr>
  </tbody>
</table>
<p>许多第三方的服务提供的 API 要自己去了解如何使用，这里&amp;后续不会做太多的介绍。</p>
<p>通常而言一个网站的 JS 代码也会有两个部分组成：一部分是服务器端代码，另一部分是客户端代码。</p>
<p>客户端代码就是访问网页的时候再本机运行的代码，而服务端代码即服务再服务端提供，客户端使用 api 去请求对应的结果和信息等等，通常服务端代码由各种语言编写：PHP、Python、Ruby、ASP.NET、JS(but nodejs)等。</p>
<h3 id="html-引入-js-代码">HTML 引入 JS 代码</h3>
<p>为了使得代码更清晰且好组织，本文依然使用引入外部 JS 的办法进行代码结构组织，HTML 中引入相关 JS 的方法和 CSS 的方法类似但略有不同。具体代码如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;scripts/main.js&#34;</span> <span class="na">defer</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这一段代码可以加在 Head 部分，其中的 defer 属性，及 deferred 延迟，是为了让元素都加载完成后再加载 JS 部分代码，否则最好将 JS 的引入放在 <a href="https://www.freecodecamp.org/chinese/news/link-javascript-to-html-with-the-src/" target="_blank" rel="noopener">HTML 快要结束的部分</a>
（<code>&lt;/body&gt;</code> 的前一行）。避免 JS 元素对 HTML 提前进行修改导致 HTML 加载失效。</p>
<p>参考资料：<a href="https://juejin.cn/post/6992371218481414152" target="_blank" rel="noopener">async-defer</a>
 | <a href="https://realdennis.medium.com/html-script-%E4%B8%ADdefer%E8%B7%9Fasync%E6%98%AF%E4%BB%80%E9%BA%BC-1166ee88d18" target="_blank" rel="noopener">Medium</a>
</p>
<h4 id="async--defer">Async &amp; defer</h4>
<p>async 下载的时候不会阻碍网页的渲染，但是下载完成就会执行，defer 会按照指定的顺序执行，同时会等到 dom 全部加载完之后再执行，合理的运用这两个属性来加载 JS 是很重要的，具体的建议摘抄自 Mdn 如下：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240330162843.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240330162843.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240330162843.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ul>
<li><code>async</code> 和 <code>defer</code> 都指示浏览器在一个单独的线程中下载脚本，而页面的其他部分（DOM 等）正在下载，因此在获取过程中页面加载不会被阻塞。</li>
<li><code>async</code> 属性的脚本将在下载完成后立即执行。这将阻塞页面，并不保证任何特定的执行顺序。</li>
<li>带有 <code>defer</code> 属性的脚本将按照它们的顺序加载，并且只有在所有脚本加载完毕后才会执行。</li>
<li>如果脚本无需等待页面解析，且无依赖独立运行，那么应使用 <code>async</code>。</li>
<li>如果脚本需要等待页面解析，且依赖于其他脚本，调用这些脚本时应使用 <code>defer</code>，将关联的脚本按所需顺序置于 HTML 的相应 <code>&lt;script&gt;</code> 元素中。</li>
</ul>
<h3 id="调试-js-代码">调试 JS 代码</h3>
<p>JS 有几种调试 debug 的方式，按照个人现阶段的理解，可以分为两类：一是主要针对 NodeJS 类的<strong>JavaScript on the server</strong>的调试，配置起来相对简单，只需要安装好 Node 在 Vsocde 中使用 Nodejs 进行调试即可。</p>
<ol>
<li>使用 NodeJS + VsCode 进行本地调试，也可以直接使用 <code>node &lt;yourjsfile&gt;.js</code> 执行，如果是在 Vscode 的终端中执行也会触发调试界面，非常方便。</li>
<li>【废弃】SpiderMonkey 中下载 JavaScript Shell 直接执行 JS 文件或者进入可交互终端。</li>
<li>【不常用】浏览器开发者环境中的控制台进行调试。</li>
</ol>
<p>二则主要用于<strong>JaveScript inside the browser</strong>的调试，最常见的是：</p>
<ul>
<li>浏览器 F12 进入开发者环境中的控制台进行调试</li>
<li><strong>VsCode</strong> + 以下两个插件：<strong>LiveServer</strong>+<strong>JavaScript Debugger</strong>（原 Debugger for Chrome） 进行调试。</li>
</ul>
<p>顺带一提这里的<strong>JavaScript Debugger</strong>建议使用预览版本，官方插件中有指引。具体如下：</p>



  
  

<blockquote class="alert-blockquote alert-quota">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Quota</span>
  </p>
  <p><ul>
<li>Open the extensions view (ctrl+shift+x) and search for <code>@builtin @id:ms-vscode.js-debug</code></li>
<li>Right click on the <code>JavaScript Debugger</code> extension and <code>Disable</code> it.</li>
<li>Search for <code>@id:ms-vscode%%  %%.js-debug-nightly</code> in the extensions view.</li>
<li>Install that extension.</li>
</ul>

</blockquote>
<p>LiveServer 可以直接启动对应端口的进程，查看对应的最终效果，使用很简单这里不过多介绍，假设其启动的服务在 3000 端口，JavaScript Debugger 可以做以下配置。</p>
<p>而<strong>JavaScript Debugger</strong>使用的时候需要新建 Lauch.json，使用 launch 模式进行 debug，具体配置如下（使用 edge 进行调试）该部分参考资料：<a href="https://juejin.cn/post/7111978793220177934" target="_blank" rel="noopener">在VsCode中使用JavaScript Debugger</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>json</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="s2">&#34;configurations&#34;</span><span class="err">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;msedge&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;request&#34;</span><span class="p">:</span> <span class="s2">&#34;launch&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;launch vuejs: chrome&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;url&#34;</span><span class="p">:</span> <span class="s2">&#34;http://localhost:3000/&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;webRoot&#34;</span><span class="p">:</span> <span class="s2">&#34;${workspaceFolder}&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// &#34;breakOnLoad&#34;: true,
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="nt">&#34;sourceMaps&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;sourceMapPathOverrides&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;webpack:///src/*&#34;</span><span class="p">:</span> <span class="s2">&#34;${webRoot}/*&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>url 为本地需要调试的项目地址</li>
<li>sourceMaps: true 开启源码映射功能，从而更好的调试源码</li>
<li>设置源码映射路径 <code>sourceMapPathOverrides</code> ，上面映射了 webpack 打包后的源码文件夹到项目的 src 目录；其他需要映射的目录，可以自行添加。</li>
</ul>
<p>替换为自己对应的路径后即可开始调试，在 Js 中打下的断点就会生效了，这里暂时没使用 Attach 模式，后续用到在研究。</p>
<p>了解代码调试和运行是学习语言的基础，对这些有所熟悉之后就可以开始学习和尝试编写 JS 代码了。</p>
]]></content:encoded>
    </item>
    <item>
      <title>LearnWeb03-CSS01-基础CSS规则</title>
      <link>https://aikenh.cn/posts/learnweb03-css01-%E5%9F%BA%E7%A1%80css%E8%A7%84%E5%88%99/</link>
      <pubDate>Wed, 31 Jan 2024 15:58:10 +0000</pubDate>
      <guid>https://aikenh.cn/posts/learnweb03-css01-%E5%9F%BA%E7%A1%80css%E8%A7%84%E5%88%99/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-summary&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Summary&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;在前文 web 入门中已经简单介绍了 CSS 是如何起作用，如何与 HTML 进行相互合作的，本篇主要简单介绍如何编写 CSS 文件中的各种样式。&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>在前文 web 入门中已经简单介绍了 CSS 是如何起作用，如何与 HTML 进行相互合作的，本篇主要简单介绍如何编写 CSS 文件中的各种样式。</p>

</blockquote>
<p>ref: <a href="https://developer.mozilla.org/zh-CN/docs/Learn/Getting_started_with_the_web/CSS_basics" target="_blank" rel="noopener">mdn css入门</a>
 | <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/Reference" target="_blank" rel="noopener">MDN css属性大全</a>
</p>
<p>在本文及后续的尝试中，都使用单独 CSS 文件外挂的格式，该种格式的结构会更清晰，即将下述代码放入 HTML 文件的 Head 部分。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;styles/style.css&#34;</span> <span class="p">/&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>href 部分需要替换为自己实际存放 css 文件的地址即可，此外也简单重复一下剩下的两种使用 CSS 的方式：内部样式表和内联样式表</p>
<ul>
<li><strong>内部样式表</strong>即在 HTML 的 Head 部分添加 <code>&lt;style&gt;your css code&lt;/style&gt;</code> 将 CSS 代码都包裹起来</li>
<li><strong>内联样式表</strong>即在特定元素中定义 style 属性，<code>&lt;p style=&quot;your css code&quot;&gt;</code> 在 style 属性中填充需要的 CSS 代码。</li>
</ul>
<p>接下来进入正文，讲解 css 部分的组成和编写规则。</p>
<h2 id="pattern-基础范式">Pattern 基础范式</h2>
<blockquote>
<p>The Principle to Write Css.</p>
</blockquote>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240131161211.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240131161211.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240131161211.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>这是一个最基本的 CSS 结构，更为专业的名称是 <strong>CSS 规则集</strong>（简称为规则），其组成分成一下几个部分：</p>
<ul>
<li><strong>选择器 Selector</strong>：类似表格中的筛选，筛选这个规则使用的范围，针对 Class、ID、Tag 等不同类型有不同的选择器写法</li>
<li><strong>属性 Property</strong>: 选择要修改的属性，如颜色，大小，位置灯多重类型。</li>
<li><strong>属性值 Property value</strong>: 各种对应属性的取值，如具体的哪个颜色，字体多大等。</li>
<li><strong>声明 Declaration</strong>：由属性和属性值组成的一条单独的规则，指定一种特定的样式。</li>
</ul>
<p>上述结构称为规则<strong>集</strong>，因为其可以同时包含多个规则（即声明），编写时有以下约定：</p>
<ul>
<li>每个规则使用 <code>;</code> 作为结尾的分割</li>
<li>同一个规则集的规则需要编写在 <code>{}</code> 之中</li>
<li>属性和属性值为 K-V 对，声明时使用 <code>:</code> 作为分割符，且属性和值均不区分大小写</li>
</ul>
<h2 id="注释方法">注释方法</h2>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="c">/*
</span></span></span><span class="line"><span class="cl"><span class="c">all between those two symbol is comment.
</span></span></span><span class="line"><span class="cl"><span class="c">*/</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="选择器使用基础">选择器使用基础</h2>
<p>该部分主要介绍如何使用选择器选中、多选不同的元素，更好更灵活的使用选择器来构建出各种不同的效果。</p>
<h3 id="不同类型选择器定义">不同类型选择器定义</h3>
<p>除了使用标签名称进行选择，大多数时候会希望使用更加 specific 的 Class 等去选择需要渲染的内容，才能使得风格更加多样可定制。下面列出一些常见的选择器定义方法，<a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Building_blocks/Selectors" target="_blank" rel="noopener">更多的还是参阅MDN</a>
</p>
<table>
  <thead>
      <tr>
          <th>选择器名称</th>
          <th>选择的内容</th>
          <th>示例</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>元素选择器（也称作标签或类型选择器）</td>
          <td>所有指定类型的 HTML 元素</td>
          <td><code>p</code>  <br>选择 <code>&lt;p&gt;</code></td>
      </tr>
      <tr>
          <td>ID 选择器</td>
          <td>具有特定 ID 的元素。单一 HTML 页面中，每个 ID 只对应一个元素，一个元素只对应一个 ID</td>
          <td><code>#my-id</code>  <br>选择 <code>&lt;p id=&quot;my-id&quot;&gt;</code> 或 <code>&lt;a id=&quot;my-id&quot;&gt;</code></td>
      </tr>
      <tr>
          <td>类选择器</td>
          <td>具有特定类的元素。单一页面中，一个类可以有多个实例</td>
          <td><code>.my-class</code>  <br>选择 <code>&lt;p class=&quot;my-class&quot;&gt;</code> 和 <code>&lt;a class=&quot;my-class&quot;&gt;</code></td>
      </tr>
      <tr>
          <td>属性选择器</td>
          <td>拥有特定属性的元素</td>
          <td><code>img[src]</code>  <br>选择 <code>&lt;img src=&quot;myimage.png&quot;&gt;</code> 但不是 <code>&lt;img&gt;</code></td>
      </tr>
      <tr>
          <td>伪类选择器</td>
          <td>特定状态下的特定元素（比如鼠标指针悬停于链接之上）</td>
          <td><code>a:hover</code>  <br>选择仅在鼠标指针悬停在链接上时的 <code>&lt;a&gt;</code> 元素</td>
      </tr>
  </tbody>
</table>
<h2 id="引入字体文件httpsdevelopermozillaorgzh-cndocslearncssstyling_textweb_fonts">引入<a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Styling_text/Web_fonts" target="_blank" rel="noopener">字体文件</a>
</h2>
<p>如果需要修改/导入字体文件，可以类似导入 css 文件一般，导入字体文件，一般有两种方式，一种是导入在线字体（<strong>不推荐</strong>，访问 google 字体库时可能会导致用户的 IP 泄漏），或者导入本地字体（推荐）。</p>
<p>导入字体的例子如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="o">&lt;</span><span class="nt">link</span> <span class="nt">rel</span><span class="o">=</span><span class="s2">&#34;stylesheet&#34;</span> <span class="nt">href</span><span class="o">=</span><span class="s2">&#34;https://fonts.googleapis.com/css?family=Open+Sans&#34;</span> <span class="o">/&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>然后在 CSS 文件中全局/局部定义字体，这里给一个全局定义的例子，后面可以通过局部的规则对其进行覆盖：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">html</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="n">font_family</span><span class="p">:</span> <span class="s2">&#34;Open Sans&#34;</span><span class="p">,</span> <span class="kc">sans-serif</span> <span class="c">/* 这应该是从Google Fonts能得到的其余输出*/</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>获取字体的手段：<a href="https://developers.google.com/fonts" target="_blank" rel="noopener">GoogleFonts</a>
，Github，推荐将字体下载到本地之后再进行挂载，或者使用安全的 <a href="https://web.mit.edu/jmorzins/www/fonts.html" target="_blank" rel="noopener">web通用字体</a>
如：Arial、Times New Roman、Courier New。</p>
<p>导入本地字体的指引可以参考 <a href="https://www.iware.com.tw/qa-508.html" target="_blank" rel="noopener">css 字体嵌入方法</a>
，实际上没有导入在线字体方便，需要考虑加载时间，导入支持各种浏览器的字体，优先加载用户本地字体等。</p>
<h2 id="css-的一切皆盒子">CSS 的一切皆盒子</h2>
<blockquote>
<p>COPY FROM MDN</p>
</blockquote>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240131170500.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240131170500.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240131170500.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>CSS 布局主要是基于盒子模型。在你的页面上占用空间的每个盒子都有类似的属性：</p>
<ul>
<li><code>padding</code>（内边距）：是指内容周围的空间。在下面的例子中，它是段落文本周围的空间。</li>
<li><code>border</code>（边框）：是紧接着内边距的线。</li>
<li><code>margin</code>（外边距）：是围绕元素边界外侧的空间。</li>
</ul>
<p>创建一个这样的文本块还会需要用到一下的这些规则集：</p>
<ul>
<li><code>width</code>：元素的宽度</li>
<li><code>background-color</code>：元素内容和内边距底下的颜色</li>
<li><code>color</code>：元素内容（通常是文本）的颜色</li>
<li><code>text-shadow</code>：为元素内的文本设置阴影</li>
<li><code>display</code>：设置元素的显示模式</li>
</ul>
<p>设置整个 <code>&lt;body&gt;</code> 内容块的实例：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">body</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">width</span><span class="p">:</span> <span class="mi">600</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">margin</span><span class="p">:</span> <span class="mi">0</span> <span class="kc">auto</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">background-color</span><span class="p">:</span> <span class="mh">#ff9500</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">padding</span><span class="p">:</span> <span class="mi">0</span> <span class="mi">20</span><span class="kt">px</span> <span class="mi">20</span><span class="kt">px</span> <span class="mi">20</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">border</span><span class="p">:</span> <span class="mi">5</span><span class="kt">px</span> <span class="kc">solid</span> <span class="kc">black</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>width 限制了整个 body 的宽度一直为 600 个像素</li>
<li><code>margin: 0 auto;</code> 当你在 <code>margin</code> 或 <code>padding</code> 这样的属性上设置两个值时，第一个值影响元素的上下方向（在这个例子中设置为 <code>0</code>）；第二个值影响左右方向。(这里，<code>auto</code> 是一个特殊的值，它将可用的水平空间平均分配给左和右）。如 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/margin#%E8%AF%AD%E6%B3%95" target="_blank" rel="noopener">Margin 语法</a>
中所记载的那样，你也可以使用一个、两个、三个或四个值</li>
<li><code>padding: 0 20px 20px 20px;</code> 我们给内边距设置了四个值来让内容四周产生一点空间。这一次我们不设置上方的内边距，设置右边，下方，左边的内边距为 20 像素。值以上、右、下、左的顺序排列。与 <code>margin</code> 一样，你也可以像 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/padding#%E8%AF%AD%E6%B3%95" target="_blank" rel="noopener">Padding 语法</a>
中所记载的那样，使用一个、两个、三个或四个值。</li>
<li><code>border: 5px solid black;</code> 这是为边框的宽度、样式和颜色设置的值。在本例中，它是一个在主体的所有侧面的 5 像素宽的纯黑色边框。</li>
</ul>
<p>默认的标题样式并不美观，可以按照以下方式做一些简单的改善：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">h1</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">margin</span><span class="p">:</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">padding</span><span class="p">:</span> <span class="mi">20</span><span class="kt">px</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">color</span><span class="p">:</span> <span class="mh">#00539f</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">text-shadow</span><span class="p">:</span> <span class="mi">3</span><span class="kt">px</span> <span class="mi">3</span><span class="kt">px</span> <span class="mi">1</span><span class="kt">px</span> <span class="kc">black</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>padding：标题的顶部和底部内边距设置为 20 像素。</li>
<li>text-shadow：
<ul>
<li>第一个像素值设置阴影与文本的<strong>水平偏移量</strong>：它横移的距离。</li>
<li>第二个像素值设置阴影与文本的<strong>垂直偏移量</strong>：它向下移动的距离。</li>
<li>第三个像素值设置阴影的<strong>模糊半径</strong>。一个更大的值会产生一个更模糊的阴影。</li>
<li>第四个值设置阴影的基色。</li>
</ul>
</li>
</ul>
<p>最后，我们把<strong>图像居中</strong>来使页面更美观。可以复用 body 的 <code>margin: 0 auto</code>，但有一些差异，需要额外的设置来使 CSS 发挥作用。</p>
<p><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/body" target="_blank" rel="noopener"><code>&lt;body&gt;</code></a>
 元素是<strong>块级</strong>元素，意味着它占据了页面的空间并且能够赋予外边距和其他改变间距的值。而图片是<strong>行级</strong>元素，不具备块级元素的一些功能。所以为了使图像有外边距，我们必须使用 <code>display: block</code> 给予其块级行为。</p>



  
  

<blockquote class="alert-blockquote alert-callout">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Callout</span>
  </p>
  <p><strong>备注：</strong> 以上说明假定所选图片小于页面宽度（600 像素）。更大的图片会溢出 body 并占据页面的其他位置。要解决这个问题，可以： 1）使用<a href="https://en.wikipedia.org/wiki/Raster_graphics_editor" target="_blank" rel="noopener">图片编辑器</a>
 来减小图片宽度； 2）用 CSS 限制图片大小，即减小 <code>&lt;img&gt;</code> 元素 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/width" target="_blank" rel="noopener"><code>width</code></a>
 属性的值。</p>

</blockquote>



  
  

<blockquote class="alert-blockquote alert-callout">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Callout</span>
  </p>
  <p><strong>备注：</strong> 如果你暂时不能理解 <code>display: block</code> 和块级元素与行级元素的差别也没关系；随着你对 CSS 学习的深入，你将明白这个问题。<code>display</code> 属性的更多信息请查看 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/display" target="_blank" rel="noopener">display 属性参考页面</a>
。</p>

</blockquote>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">img</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">width</span><span class="p">:</span> <span class="mi">400</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">align-self</span><span class="p">:</span> <span class="kc">center</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">margin</span><span class="p">:</span> <span class="mi">0</span> <span class="kc">auto</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">display</span><span class="p">:</span> <span class="kc">block</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="example-最终效果">Example 最终效果</h2>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">html</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">font-family</span><span class="p">:</span> <span class="s2">&#34;Open Sans&#34;</span><span class="p">,</span> <span class="kc">sans-serif</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">font-size</span><span class="p">:</span> <span class="mi">20</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c">/* h1 {
</span></span></span><span class="line"><span class="cl"><span class="c">    font-size: 50px;
</span></span></span><span class="line"><span class="cl"><span class="c">    text-align: center;
</span></span></span><span class="line"><span class="cl"><span class="c">  } */</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">h1</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">margin</span><span class="p">:</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">padding</span><span class="p">:</span> <span class="mi">20</span><span class="kt">px</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">color</span><span class="p">:</span> <span class="mh">#00539f</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">text-shadow</span><span class="p">:</span> <span class="mi">3</span><span class="kt">px</span> <span class="mi">3</span><span class="kt">px</span> <span class="mi">1</span><span class="kt">px</span> <span class="kc">black</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl"><span class="nt">p</span><span class="o">,</span><span class="nt">li</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">font-size</span><span class="p">:</span> <span class="mi">16</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">line-height</span><span class="p">:</span> <span class="mi">2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">letter-spacing</span><span class="p">:</span> <span class="mi">1</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">html</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">background-color</span><span class="p">:</span> <span class="mh">#2050b8</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">body</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">width</span><span class="p">:</span> <span class="mi">600</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">margin</span><span class="p">:</span> <span class="mi">0</span> <span class="kc">auto</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">background-color</span><span class="p">:</span> <span class="mh">#ff9500</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">padding</span><span class="p">:</span> <span class="mi">0</span> <span class="mi">20</span><span class="kt">px</span> <span class="mi">20</span><span class="kt">px</span> <span class="mi">20</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">border</span><span class="p">:</span> <span class="mi">5</span><span class="kt">px</span> <span class="kc">solid</span> <span class="kc">black</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"><span class="nt">img</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">width</span><span class="p">:</span> <span class="mi">400</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">align-self</span><span class="p">:</span> <span class="kc">center</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">margin</span><span class="p">:</span> <span class="mi">0</span> <span class="kc">auto</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">display</span><span class="p">:</span> <span class="kc">block</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">  </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240131172103.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240131172103.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240131172103.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
]]></content:encoded>
    </item>
    <item>
      <title>LearnWeb02-HTML01-基础的标签</title>
      <link>https://aikenh.cn/posts/learnweb02-html01-%E5%9F%BA%E7%A1%80%E7%9A%84%E6%A0%87%E7%AD%BE/</link>
      <pubDate>Wed, 31 Jan 2024 15:00:58 +0000</pubDate>
      <guid>https://aikenh.cn/posts/learnweb02-html01-%E5%9F%BA%E7%A1%80%E7%9A%84%E6%A0%87%E7%AD%BE/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-intro&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Intro&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;在 Web 入门，How HTML Work 部分已经简单介绍过，HTML 是一种定义内容结构的标记语言，通过一系列标记（确定其表现形式）和对应内容组成的元素，嵌套，排列，构成完整的页面。本文主要是整理和熟悉一下基础的标记元素&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-intro">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Intro</span>
  </p>
  <p>在 Web 入门，How HTML Work 部分已经简单介绍过，HTML 是一种定义内容结构的标记语言，通过一系列标记（确定其表现形式）和对应内容组成的元素，嵌套，排列，构成完整的页面。本文主要是整理和熟悉一下基础的标记元素</p>

</blockquote>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240131110224.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240131110224.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240131110224.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>REF: <a href="https://developer.mozilla.org/zh-CN/docs/Learn/Getting_started_with_the_web/HTML_basics" target="_blank" rel="noopener">HTML 入门</a>
</p>
<p>从上述图像可以看到一个基本的 HTML 元素的构成，元素的 Tag 可以包含属性，<strong>多个属性之间用空格隔开</strong>，Class 属性可以为元素标识名称，进而为其指定 Style 等。</p>
<p>属性通常为 K-V 键值对，attr=&ldquo;value&rdquo; 的形式呈现，这里引号可以是单或者双，甚至可以没有，但是没有引号有时候会导致问题，所以建议保持使用引号的风格去编写。</p>
<h2 id="headoverview-部分">Head/Overview 部分</h2>
<p>参考网站中的范例如下，一个基本的 HTML 文件有以下这些可以注意的地方：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="cp">&lt;!doctype html&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;en-US&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;utf-8&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;viewport&#34;</span> <span class="na">content</span><span class="o">=</span><span class="s">&#34;width=device-width&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span>My test page<span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;images/firefox-icon.png&#34;</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;My test image&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li><code>&lt;head&gt;</code> 就如 cpp 中的 head 文件，定义一些不用于向用户显示的内容，给浏览器的关键词，字符集声明，页面描述等内容</li>
<li><code>&lt;meta charset=&quot;utf-8&quot;&gt;</code> 定义文档使用的字符串编码类型，utf-8 支持世界上大部分语言的渲染，避免因为中文等出现乱码的情况。</li>
<li><code>&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width&quot;&gt;</code> 视口元素，可以确保页面以视口宽度进行渲染，避免移动端浏览器上因页面过宽导致缩放。</li>
<li><code>&lt;title&gt;</code> 对当前网页的描述和注解，显示在标签栏中，以及收藏时显示的文字</li>
<li><code>&lt;body&gt;</code> 部分则是包含网站的全部需要显示的内容。</li>
</ul>
<h2 id="body-部分常见元素">Body 部分常见元素</h2>
<p><strong>标题</strong>：例如 markdown 中的 <code>##</code> 定义各级标题，Html 中使用 <code>&lt;hn&gt;</code> n 从 1-6 定义网页的各级标题，一般最多用到 3-4 级；</p>
<p><strong>段落</strong>：按照 word 中的段落来理解，基本为常规的文本内容，段落间和段落内的间距会有所区别，使用标签 <code>&lt;p&gt;</code> 来定义段落；</p>
<p><strong>列表</strong>：分为无序列表 <code>&lt;ul&gt;</code> 和有序列表 <code>&lt;ol&gt;</code> 两种，无论是那种列表，具体的每一个列表项使用 <code>&lt;li&gt;</code> 定义，具体例子如下(列表中也可以嵌套别的列表)</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>here is a example for list<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span>item1<span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span>item2<span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>if u want ordered list, change ul to ol.<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>此外还存在<strong>空元素</strong>（图像元素），即不需要 Content 内容部分的元素，如图像元素，这是因为图像元素本身就是内容，具体的元素例子如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://&lt;img-url-&gt;&#34;</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;the alias of this img&#34;</span> <span class="p">/&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>图像元素的 tag 即 <code>img</code>, src 定义了图像的来源，可以是网站或者文件路径，alt 为图像的注解，为视障人士或者图像加载过程中，显示的图像元素的占位或注解。</p>
<blockquote>
<p>空元素无需再末尾添加/但是加上也没问题，加上也能使其作为有效的 XML 格式</p>
</blockquote>
<p><strong>超链接</strong>：例如 markdown 中的 <code>[]()</code>, Html 使用 Anchor 标签 <code>&lt;a&gt;</code> 和指定属性 href 即 <code>()</code> 以及显示的内容(content)也即 <code>[]</code> 来共同完成一个超链接, 以跳转到 google 为例：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>markdown</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">[<span class="nt">google</span>](<span class="na">https://www.google.com</span>)</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#39;https://www.google.com&#39;</span><span class="p">&gt;</span>google<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="example-尝试">Example 尝试</h2>
<p>尝试一个 Dashboard 界面，加载一张基础图片，然后使用各个元素来列出一些服务。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="cp">&lt;!DOCTYPE html&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span>Aikenhong Dashboard for Home Sevices<span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;UTF-8&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;viewport&#34;</span> <span class="na">content</span><span class="o">=</span><span class="s">&#34;width=device-width, initial-scale=1.0&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span> Welcome to Aikenhong Dashboard for Home Services<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/80a5366f89dfbd27ec46f669e0eac84.jpg&#34;</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;Aikenhong Logo&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">H3</span><span class="p">&gt;</span> Intro:
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span> 网站对中文提供支持，希望大家有一个友好的访问体验。<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">H3</span><span class="p">&gt;</span> Links <span class="p">&lt;/</span><span class="nt">H3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://www.aikenh.cn/&#34;</span><span class="p">&gt;</span>myBlog<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://www.aikenh.cn/about/&#34;</span><span class="p">&gt;</span>About Us<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://metisy.cool/&#34;</span><span class="p">&gt;</span>Metisy<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;&lt;/</span><span class="nt">li</span><span class="p">&gt;&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="fi">FI</h2>
]]></content:encoded>
    </item>
    <item>
      <title>LearnWeb01-DevPipeline</title>
      <link>https://aikenh.cn/posts/learnweb01-devpipeline/</link>
      <pubDate>Tue, 30 Jan 2024 10:40:23 +0000</pubDate>
      <guid>https://aikenh.cn/posts/learnweb01-devpipeline/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-summary&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Summary&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;Familiar with the pipeline of how to build a website, how to organize the files, etc&amp;hellip;&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>Familiar with the pipeline of how to build a website, how to organize the files, etc&hellip;</p>

</blockquote>
<h2 id="start-design">Start Design</h2>
<p>开始设计一个网站的时候，可以从以下三个方面入手来启动整个开发设计过程：网站的主题-&gt;基础的一些内容-&gt;整体的外观设计（草稿）</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240130115132.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240130115132.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240130115132.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>更具体一些：确定完要制作的网页，可以绘制草图有一个粗浅的整体效果，然后指定文本、图像、色彩、字体等资源，就可以开始制作了。</p>
<h2 id="file-structure">File Structure</h2>
<p>关于项目中的文件命名，需要注意的是以下的三点，建议养成这样的规范去建立网页文件夹。</p>
<ul>
<li><strong>建议使用完全小写来命名文件</strong>，webserver 是大小写敏感的，所以复杂的大小写关系容易导致访问不到文件。</li>
<li><strong>尽量不要使用空格</strong>，空格可能会破坏链接被视为两个文件等，如果没有被区分很多服务器也需要使用 %20 对空格进行替换</li>
<li><strong>尽量使用连字符代替下划线进行文件命名</strong>，google 搜索引擎将连字符作为单词的分割符，而不会识别下划线</li>
</ul>
<p>而文件存储结构部分，通常而言，有以下的关键文件和文件夹结构，在很多场景下也会将 image 等文件夹放到 static 文件夹中。</p>
<ul>
<li>index.html</li>
<li>styles: 存放 css 文件</li>
<li>images: 存放图片等媒体资源文件</li>
<li>scripts: 存放 js 等脚本代码文件</li>
</ul>
<p>资源的文件路径一般而言以 html 为 Basepath，然后根据上下级关系确认索引地址即可。</p>
<h2 id="develop-online">Develop Online</h2>
<p>一些 web 的在线开发和预览网站，可以通过编写 html,css,js 直接获取预览效果，对于一些简单的 web 应用可以直接在线开发，但是无法实现资源的存储和托管等。</p>
<ul>
<li><a href="https://jsfiddle.net/" target="_blank" rel="noopener">JSFiddle</a>
</li>
<li><a href="https://glitch.com/" target="_blank" rel="noopener">Glitch</a>
</li>
<li><a href="http://jsbin.com/" target="_blank" rel="noopener">JSBin</a>
</li>
<li><a href="https://codepen.io/" target="_blank" rel="noopener">CodePen</a>
</li>
</ul>
<p>这些线上集成开发环境还是比较方便好用的，可以尝试自己更喜欢哪一个。</p>
<h2 id="publish">Publish</h2>
<blockquote>
<p>这里在家庭服务器中已经有过相关的介绍就不在赘述，简单描述一下流程</p>
</blockquote>
<ol>
<li>从域名服务商获取域名</li>
<li>获取 SSL 证书(https)</li>
<li>具有公网 IP 的服务器部署服务到指定端口/ GITHUB Page 等托管网站</li>
<li>使用 Nginx/Candy 之类的实现本地端口转发和域名解析</li>
<li>服务商实现 DNS 解析，将域名解析到对应的 IP 地址（托管网站无需处理）</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>LearnWeb00-Web入门</title>
      <link>https://aikenh.cn/posts/learnweb00-web%E5%85%A5%E9%97%A8/</link>
      <pubDate>Sun, 28 Jan 2024 21:25:30 +0000</pubDate>
      <guid>https://aikenh.cn/posts/learnweb00-web%E5%85%A5%E9%97%A8/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-summary&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Summary&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;Web 前端开发者路线学习，基本的目的是能够为自己想做的项目搭建前端界面，从 web 开始再到各个移动设备的前端 UI，基于 Mdn 课程，Roadmap 具体项目逐步推进对各个知识点的学习。&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>Web 前端开发者路线学习，基本的目的是能够为自己想做的项目搭建前端界面，从 web 开始再到各个移动设备的前端 UI，基于 Mdn 课程，Roadmap 具体项目逐步推进对各个知识点的学习。</p>

</blockquote>
<p>根据下面的课程、Roadmap、搭建自己的知识架构，在搭建过程中结合具体的项目，包括自己部署的界面去逐步实践，完善和熟悉整个知识体系和技术栈，并通过和现代 AI 辅助工具的合作，建立自己独立的前端开发流。</p>
<ul>
<li><a href="https://metisy.cool/library/library/46/series/398/manga/1714?incognitoMode=false" target="_blank" rel="noopener">Roadmap For Beginner</a>
</li>
<li><a href="https://metisy.cool/library/library/46/series/397/pdf/1712?incognitoMode=false" target="_blank" rel="noopener">Roadmap For All</a>
</li>
<li><a href="https://developer.mozilla.org/zh-CN/docs/Learn/Front-end_web_developer" target="_blank" rel="noopener">Mdn Web Tutor</a>
</li>
</ul>
<h2 id="be-ready-准备以及基础了解">Be Ready 准备以及基础了解</h2>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240128213825.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240128213825.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240128213825.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ul>
<li>基础：开发环境准备、页面设计、文件架构规划（由于网站需要包含多种代码、文本、素材、因此如何组织文件是相当重要的）</li>
<li>语言：HTML 、CSS、JS 三驾马车为一个网页必不可少的要素，通过结合各自不同的功能来实现多样化的页面设计。</li>
</ul>
<h2 id="whats-web">What&rsquo;s WEB</h2>
<p><a href="https://www.youtube.com/watch?v=O_GWbkXIqEY&amp;list=PLo3w8EB99pqLEopnunz-dOOBJ8t-Wgt2g&amp;index=1" target="_blank" rel="noopener">What&rsquo;s WEB?</a>
 通过 URL 统一资源定位符向服务器请求 HTML，HTML 通过包含的信息告诉 Browse 需要额外的信息来呈现该页面，因此基于 HTML 提供的信息 web browser 继续请求资源、CSS、JS 等文件，并将这些文件按照 HTML 的描述进行组合最终呈现完整的页面。</p>
<iframe width="560" height="315" src=" https://www.youtube.com/embed/O_GWbkXIqEY?si=4KI068N1LN2k422F" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
<h3 id="how-html-work">How HTML Work</h3>
<p><a href="https://www.youtube.com/watch?v=PORRrz3Y8Vc&amp;list=PLo3w8EB99pqLEopnunz-dOOBJ8t-Wgt2g&amp;index=2" target="_blank" rel="noopener">How HTML(Hyper Text Markup Language) Work?</a>
 HTML 提供了一个标准（告诉 browser）用<strong>特定标签</strong>来描述一些纯文本，这些标签就对应特定的文本渲染方式。</p>



  
  

<blockquote class="alert-blockquote alert-quota">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Quota</span>
  </p>
  <p>HTML is a descriptive language that allow us to tell a web browser how to handle text content. HTML 是一个描述性语言，允许告知网页浏览器如何去处理这些文本内容并进行对应的渲染。</p>

</blockquote>
<p>更具体一点可以说以下面这个例子来说：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240131110224.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240131110224.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240131110224.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>



  
  

<blockquote class="alert-blockquote alert-quota">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Quota</span>
  </p>
  <p>HTML 不是一门编程语言，而是一种用于定义内容结构的标记语言。HTML 由一系列的<a href="https://developer.mozilla.org/zh-CN/docs/Glossary/Element" target="_blank" rel="noopener">元素</a>
组成，这些元素可以用来包围不同部分的内容，使其以某种方式呈现或者工作。一对<a href="https://developer.mozilla.org/zh-CN/docs/Glossary/Tag" target="_blank" rel="noopener">标签</a>
可以为一段文字或者一张图片添加超链接，将文字设置为斜体，改变字号，等等。</p>

</blockquote>
<p><strong>HTML 标签</strong>：</p>
<ul>
<li>用 <code>&lt;&gt;</code> 包裹<strong>标签名称</strong>这里是 p -&gt; <code>&lt;p&gt;</code>，</li>
<li>可以在其之上通过更多的<strong>属性</strong>来提供更多的信息 <code>&lt;p lang='en'&gt;</code> ，这里的 lang 为<strong>属性名称</strong>，‘en’为<strong>属性值</strong>，值得一提的是 <strong>class 属性</strong>可以为元素提供一个<strong>标识名称</strong>，用于后续 css 中为元素定义各种样式。</li>
<li>将<strong>标签和对应的结束标签</strong>将文本段落，即<strong>内容</strong>，包围起来，就形成了<strong>HTML 元素</strong>（段落）：<code>&lt;p&gt; some text &lt;/p&gt; </code></li>
<li>通过<strong>嵌套组合各种元素</strong>，就可以创建一个 HTML 文档了。</li>
</ul>
<p>基础的架构如下 ：</p>
<ul>
<li><code>&lt;html&gt; &lt;/html&gt;</code> 包裹文件中 HTMl 的部分（文件中可以包含其他的 css，js 等内容）</li>
<li><code>&lt;!DOCTYPE html&gt; </code>  <!-- 告诉 Browser 这是一个标准的 HTML 文档 --></li>
<li>如 <code>head</code> <code>body</code> <code>title</code> 之类的元素/标签的制定由 W3C(world wide web consortium) 确定和维护，可以在 MDN web 文档中查看所有 Tag 的文档，相对基本文档更加易于理解。</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="cp">&lt;!DOCTYPE html&gt;</span>  <span class="c">&lt;!-- 告诉Browser这是一个标准的HTML文档 --&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span> My cat have not eat yet.
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span> My cat is <span class="p">&lt;</span><span class="nt">strong</span><span class="p">&gt;</span>very<span class="p">&lt;/</span><span class="nt">strong</span><span class="p">&gt;</span> cute <span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>HyperText 只是一个花哨的词语，意味着 HTML 可以创建一个到另一个 HTML 文件的连接，类似超链接，实现页面的跳转。</p>
<p>页面的跳转对应的为 a 元素，可以通过如下的超文本实现页面跳转功能（也就是超链接）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">a</span> <span class="na">herf</span><span class="o">=</span><span class="s">&#34; https://aikenh.cn/&#34;</span><span class="p">&gt;</span>Homepage<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>总结一下，也就是 HTML 是为了 Browser 理解文本的一种语言，通过 W3C 指定的各种标签/元素规则来理解&amp;实现 Browser 对页面的渲染。</p>
<h3 id="how-css-work">How CSS work</h3>
<p><a href="https://www.youtube.com/watch?v=Y02yI1OfZjI&amp;list=PLo3w8EB99pqLEopnunz-dOOBJ8t-Wgt2g&amp;index=3" target="_blank" rel="noopener">What&rsquo;s CSS &amp; How it Style the web pages</a>
? CSS 也是一种描述性语言，但描述的不是文本的“语义”，而是对每一种 HTML 元素的外观和感觉进行描述，例如描述 <code>&lt;head&gt;content&lt;/head&gt;</code> Head,strong 这类元素应该如何呈现，就像是一种 HTML 的化妆（样式补充）</p>
<blockquote>
<p>CSS (Cascading Style Sheets) 层叠样式表</p>
</blockquote>
<p>CSS 描述的是文本的 Presentation 表现形式，而 HTML 描述的是文本的 Semantics 语义（将表现从 HTML 分离出来避免最终页面代码混杂导致的混乱）。</p>
<p><strong>How it works?</strong> 通常使用 CSS 有三种方法：</p>
<ul>
<li>（尽量避免，缺乏灵活性且难以维护）在 HTML 标记中使用 style 属性如 <code>&lt;strong style=&quot;...&quot;&gt;</code></li>
<li>（只适用于单个 HTML 文档，通常网站由多个 HTML 组成）将 CSS 声明添加到 HTML 文档中，用 <code>&lt;style&gt; &lt;/style&gt;</code> 包围，上述代码中用 <code>&lt;html&gt;&lt;/html&gt;</code> 标签将 HTML 的代码块包裹起来就是为了和其他类型的代码区分。</li>
<li>（首选）创建单独的 CSS 文件，然后在多个 HTML 中连接特定的样式表，从而维持一致的样式特征，如：</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">herf</span><span class="o">=</span><span class="s">&#34;style.css&#34;</span> <span class="p">/&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>How to defined CSS？</strong> Starts with selector to indicate which HTML element we want to style. Then using {} to defind all the property.</p>
<p>例如我们定义上述提到的 strong 和 head 的样式就可以按照下面的方式：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>css</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="nt">strong</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">color</span><span class="p">:</span> <span class="kc">red</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">display</span><span class="p">:</span> <span class="kc">flex</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">head</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">align-items</span><span class="p">:</span> <span class="kc">center</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">display</span><span class="p">:</span> <span class="kc">flex</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>CSS 有 300 多个属性，可以定义任何方式的页面，最好<strong>了解常见</strong>的一些属性，属性的组合常常出乎你的意料，</p>
<p><strong>CSS 的另一个重要特性就是 Cascading 级联</strong>，通过不同的 Selector（类似过滤器） 可以指定不同类型的元素进行样式处理（渲染），也就是说通过 selector 的特性，一个元素可以按照某种顺序被多种样式渲染（CSS 定义了一组规则）需要的话可以在 MDN 查看，在开发者模式中也可以看到顺序：</p>
<blockquote>
<p>允许覆盖和组合</p>
</blockquote>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240129000141.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240129000141.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240129000141.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>CSS 声明一种外观和渲染形式，后续通过选择器将这些 Style 应用到各个 HTML 元素上（在同个元素上可能会出现样式的覆盖或者堆叠的情况），实现对整个页面的渲染。</p>
<h3 id="how-javascript-works">How JavaScript Works</h3>
<p><strong>JavsScript</strong> is the Progamming language at the heart of the modern web.</p>
<p>实际上 JavaScript 可以完全分成两个不同的分支（flavors）：</p>
<ol>
<li><strong>JaveScript inside the browser</strong>：用于修改 HTML、网络请求、数据处理和渲染等用于Web</li>
<li><strong>JavaScript on the server</strong>：(Nodejs)计算机控制和管理，进程和文件处理等，更接近一个普通的编程语言。</li>
</ol>
<p>两者存在许多独立的有用的库，除了语法，两者在应用和实际编写上重叠的地方很少，该视频后续主要介绍的是 Browser 中的 JS 。</p>
<p>CSS &amp; HTML 一样，可以</p>
<ul>
<li>直接在 HTML 中使用 <code>&lt;script&gt;&lt;/script&gt;</code> 元素来包裹 JS 的代码块</li>
<li>独立写在一个 js 文件中，并在 html 代码中使用 <code>&lt;script src=&quot;myScript.js&quot;&gt;</code> 将其连接到 HTML 中</li>
</ul>
<p>JS 和其他语言不一样的特点为，其自带<strong>原生的异步处理机制</strong>，可以对设定好的事件及时做出反应（触发），如下面的代码当窗口的 load 被触发了，就会执行{}中的代码，实现及时对事件做出反应。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">windows</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;load&#39;</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">})</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这种机制对用户交互界面原生的友好，如点击，加载完成等浏览器抛出事件，然后使用 JS 及时的对特定的事件做出反应。</p>
<h2 id="whats-svg">What&rsquo;s SVG</h2>
<blockquote>
<p><strong>Scalable Vector Graphics</strong> is the only vector image format for the web. 可缩放的矢量图形是网络上唯一的矢量图形。</p>
</blockquote>
<p>图片有两种主要的格式：位图&amp;矢量图；位图是简单的定义每个像素点的颜色行程的图片，web 中最常见的位图格式是 JPEG，PNG，GIF。矢量图则是一组渲染图像的函数，用这些函数来定义图像。两种图像的适用范围不同：</p>
<ul>
<li>位图用于更为细节的图像，如照片，具体的描述每个图片的像素点。</li>
<li>矢量图则更适用于，需要使用<strong>不同尺寸缩放</strong>的不太详细的图像，例如图标，因此对于 web 具备的多种分辨率场景具有无可比拟的优势。</li>
</ul>
<p>矢量图还具有一些其他的特性：1. 它是一种用标签编写的文本格式，就想 HTML 一样；2.可以用 CSS 进行样式设计；3. 他可以使用 JavaScript 编写脚本来实现一些变化。（绘制或者创建 SVG 需要很好的数学 or 很好的 SVG 绘图软件）</p>
<blockquote>
<p>Inskape, Illustrator, Sketch 是最常见的用于绘制 SVG 的软件 （2019）
or JS 库：snap.svg, Bonsai, D3.js</p>
</blockquote>
<h2 id="how-web-browsers-works">How web browsers works</h2>
<p><strong>web browser are mixing things together in order to display web.</strong> 接下来分析一下 Web Browser 需要具备什么能力来支撑这样的功能呢？</p>
<p>首先，Web Browser 需要获取(html)文件，因此实际上：</p>
<ul>
<li>最根本的一点就是其通过 HTTP/HTTPs 协议来完成网络连接，实现对文件的 C(Create) R(Read) U(Update) D(Delete)；</li>
<li>此外还可以建立双向的定向通信服务通道，和特定的服务器建立双向连接（WebSockets）</li>
<li>创建 Peer to peer 连接等。</li>
</ul>
<p>其次，需要<strong>理解和执行和渲染</strong>不同的语言，字体、图像、视频、文档等。
第三，需要具备交互式功能，可以实现文本选择，点击，滚动等。
第四，需要提供一些缓存存储功能，能够存储部分数据
第五，加密和安全管理功能，避免恶意入侵。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240129152217.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240129152217.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240129152217.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>由于页面是动态的，必须按照一定的刷新频率来对页面进行重绘，以实现预期的显示效果。</p>
<h2 id="how-www-works">How WWW works</h2>



  
  

<blockquote class="alert-blockquote alert-quota">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Quota</span>
  </p>
  <p>
</blockquote>
<ul>
<li><strong>互联网</strong>：好比地球上纵横交错的道路。</li>
<li><strong>网络连接</strong>：道路通到了村子路口。从此，村子里的苹果就可以运出去卖了。</li>
<li><strong>TCP/IP</strong>：为了将村里的苹果能规范有效的运卖出去而不出问题，村长作出如下规定：“用规格刚好 20 cm * 20 cm * 20 cm 的泡沫箱来装，之后外面又用相应规格的纸箱包裹上，最后打上透明胶”。并且要求，对方收到时，一定要外包装完好，不然就会补发。而且还给对方发了一张发货单，明确说明了，苹果有多少，是用什么方法包装的，只有货和发货单对上了，对方才会确认收货。</li>
<li><strong>DNS</strong>：突然一天，郭德纲想吃苹果，就跟于谦说，“我听说盘溪新村（域名）的苹果好，要他们那个套餐一选项啊！”，于谦一听，得，也不知道盘溪新村在哪，打开地图查（DNS）吧，一查，好嘛，江苏省苏州市（IP 地址），于是于谦去了苏州，找了村子，告诉村长，要套餐一，要用顺丰快递，并且留下了北京德云社的地址。</li>
<li><strong>HTTP</strong>：过了几天，德云社的人一看，有快递来了，来了这么一句，“只收‘顺丰’，拒收其他快递”。司机忙说，“是顺丰，是顺丰”，这才对上暗号，德云社的人收下了货。</li>
<li><strong>组成文件</strong>：送来的货可不止一车，而且也不止一种苹果，这车是红富士，那车黄富士的。
<ul>
<li><strong>代码</strong>：有点像，村长事先安排的说明书，让司机到了地方，如何卸车，货放到什么位置，而德云社的看说明书，知道什么样的苹果放到什么位置上，什么样苹果如何食用最佳，等等。</li>
<li><strong>资源</strong>：不同种类的苹果。</li>
</ul>
</li>
</ul>
<p>更&quot;专业&quot;一些的写法为：</p>
<ul>
<li><strong>网络连接</strong>: 允许你在互联网上发送和接受数据。</li>
<li><strong>TCP/IP</strong>: 传输控制协议和因特网互连协议是定义数据如何传输的通信协议，对传输的数据进行打包和封装。</li>
<li><strong>DNS</strong>: 域名系统服务器像是一本网站通讯录。当你在浏览器内输入一个网址时，浏览器获取网页之前将会查看域名系统。浏览器需要找到存放你想要的网页的服务器，才能发送 HTTP 请求到正确的地方。</li>
<li><strong>HTTP</strong>: 超文本传输协议是一个定义客户端和服务器间交流的语言的协议（<a href="https://developer.mozilla.org/zh-CN/docs/Glossary/Protocol" target="_blank" rel="noopener">protocol</a>
 ），定义传输的方式。</li>
<li><strong>组成文件</strong>: 一个网页由许多文件组成，就像商店里不同的商品一样。这些文件有两种类型：
<ul>
<li><strong>代码</strong> : 网页大体由 HTML、CSS、JavaScript 组成，不过你会在后面看到不同的技术。</li>
<li><strong>资源</strong> : 这是其他组成网页的东西的集合，比如图像、音乐、视频、Word 文档、PDF 文件。</li>
</ul>
</li>
</ul>
<h2 id="fi">FI</h2>
]]></content:encoded>
    </item>
    <item>
      <title>Windows Powershell 01 后台任务</title>
      <link>https://aikenh.cn/posts/pwsh_bgtask/</link>
      <pubDate>Sun, 28 Jan 2024 15:44:25 +0000</pubDate>
      <guid>https://aikenh.cn/posts/pwsh_bgtask/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-summary&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Summary&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;有一些希望能在后台运行的任务，例如 nohup,tmux,screen 可实现的一些功能，简单介绍以下 powershell 中的类似用法和功能。&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>有一些希望能在后台运行的任务，例如 nohup,tmux,screen 可实现的一些功能，简单介绍以下 powershell 中的类似用法和功能。</p>

</blockquote>
<p>To run a Command Prompt (cmd.exe) command in the background from PowerShell and retrieve it later, similar to sessions in <code>tmux</code>, you can use PowerShell Jobs. PowerShell Jobs allow you to start a command or script in the background and then retrieve the results later. Here&rsquo;s how you can do it:</p>
<p>从 PowerShell 在后台运行命令提示符 (cmd.exe) 命令并稍后检索它（与 <code>tmux</code> 中的会话类似），可以使用 PowerShell Jobs。 PowerShell Jobs 允许在后台启动命令或脚本，然后稍后检索结果。</p>
<p>具体的一些操作如下：</p>
<h3 id="start-a-job-in-the-background">Start a Job in the background</h3>
<p>使用 Start-Job 和 ScriptBlock 参数执行选定的命令</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nv">$job</span> <span class="p">=</span> <span class="nb">Start-Job</span> <span class="n">-ScriptBlock</span> <span class="p">{</span> <span class="n">pwsh</span><span class="p">.</span><span class="py">exe</span> <span class="p">/</span><span class="n">c</span> <span class="s2">&#34;your_command_here&#34;</span> <span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这里将 <code>your_command_here</code> 改为自己需要执行的命令，例如启动局域网内可访问的 Stable-Diffusion Webui：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nv">$job</span> <span class="p">=</span> <span class="nb">Start-Job</span> <span class="n">-ScriptBlock</span> <span class="p">{</span> <span class="n">pwsh</span><span class="p">.</span><span class="py">exe</span> <span class="p">/</span><span class="n">c</span> <span class="s2">&#34;.\webui.bat --xformers --listen&#34;</span> <span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果需要同时执行多条命令（例如执行 python 命令之前需要切换环境，默认为 base 环境）可以使用 <code>&amp;&amp;</code></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"> <span class="nv">$job</span> <span class="p">=</span> <span class="nb">Start-Job</span> <span class="n">-ScriptBlock</span> <span class="p">{</span> <span class="n">pwsh</span><span class="p">.</span><span class="py">exe</span> <span class="p">/</span><span class="n">c</span> <span class="s2">&#34;conda activate flask &amp;&amp; python .\app.py&#34;</span> <span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="check-the-job-status--retrieving-the-results"><strong>Check the Job Status</strong> &amp;&amp; <strong>Retrieving the Results</strong></h3>
<p>将任务放置于后台执行之后，可能需要检查执行的状态、结果决定是否要将其常驻于后台，可以使用 <code>Get-Job</code> 和 <code>Receive-Job</code> 命令实现</p>
<p>使用 Get-Job 可列出所有任务 ID 及状态</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>poewrshell</span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code class="language-poewrshell" data-lang="poewrshell">Get-Job</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240128155711.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240128155711.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240128155711.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>也可使用 Get-Job -ID your-task-id 只查看特定 ID 的任务，通过 Get-Job 获得 ID 和基本状态后可以使用 Receive-Job 对任务的运行进行检查。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">Receive-Job</span> <span class="n">-Id</span> <span class="nv">$job</span><span class="p">.</span><span class="n">Id</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240128160103.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240128160103.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240128160103.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>可以查看当前任务的运行状态决定是否要继续执行或者终止。</p>
<h3 id="stop-the-job--remove-the-code"><strong>Stop the Job</strong> &amp;&amp; Remove the Code</h3>
<p>当计划中止并移除后台任务，就需要使用到 Stop-Job 和 Remove-Job 命令，指令的名称都相当直观。</p>
<p>但是在移除指令之前要记得<strong>中止指令</strong>，否则会有类似的报错，同时无法移除任务：</p>
<blockquote>
<p>To remove the job, first stop the job, or use the Force parameter. (Parameter &lsquo;SessionId&rsquo;)</p>
</blockquote>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">Stop-Job</span> <span class="n">-Id</span> <span class="p">&lt;</span><span class="n">JobId</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nb">Stop-Job</span> <span class="n">-Name</span> <span class="p">&lt;</span><span class="n">JobName</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>中止完任务就可以安全的移除后台任务：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">Remove-Job</span> <span class="n">-Id</span> <span class="p">&lt;</span><span class="n">JobId</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nb">Remove-Job</span> <span class="n">-Name</span> <span class="p">&lt;</span><span class="n">JobName</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果想要直接删除作业而不停止，就需要使用 Force 参数，通常用于强制删除无响应或者停止时间过长的任务。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">Remove-Job</span> <span class="n">-Id</span> <span class="p">&lt;</span><span class="n">JobId</span><span class="p">&gt;</span> <span class="n">-Force</span>
</span></span><span class="line"><span class="cl"><span class="nb">Remove-Job</span> <span class="n">-Name</span> <span class="p">&lt;</span><span class="n">JobName</span><span class="p">&gt;</span> <span class="n">-Force</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>请记住将 <code>&lt;JobId&gt;</code> 或 <code>&lt;JobName&gt;</code> 替换为您要停止或删除的作业的实际 ID 或名称。这种方法可确保作业安全终止并从系统中删除，从而释放其正在使用的所有资源。</p>
<h3 id="fi">FI</h3>
]]></content:encoded>
    </item>
    <item>
      <title>使用Flask和Nginx为StableDiffusion添加登录鉴权</title>
      <link>https://aikenh.cn/posts/stablediffusionwebui%E9%89%B4%E6%9D%83%E8%AE%BE%E8%AE%A1/</link>
      <pubDate>Sat, 27 Jan 2024 15:42:36 +0000</pubDate>
      <guid>https://aikenh.cn/posts/stablediffusionwebui%E9%89%B4%E6%9D%83%E8%AE%BE%E8%AE%A1/</guid>
      <description>Secure and Personalize Your Web Services: A Guide to Nginx Authentication and Engaging Frontend Design</description>
      <content:encoded><![CDATA[<p>[&gt; [!summary]+</p>
<blockquote>
<p>this article purpose is to build an authority page for stable diffusion webui using nginx &amp; python/js. Which can publish my personal stable diffusion server. Wrote by GPT(try).</p>
</blockquote>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240127161828.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240127161828.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240127161828.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="introduction">Introduction</h3>
<p>In the digital age, the security and user-friendliness of web services are not just conveniences; they are necessities. Balancing robust security protocols with an engaging user experience is key to maintaining both the integrity and popularity of any online service. This blog post dives into the intricacies of securing web services using Nginx for authentication, coupled with designing an appealing frontend. Our journey begins with a practical scenario:</p>
<p><strong>publishing a stable diffusion webUI service, accessible only to an authenticated audience.</strong></p>
<h3 id="setting-up-nginx-for-secure-authentication">Setting Up Nginx for Secure Authentication</h3>
<p>Nginx excels in serving web pages and as a reverse proxy, providing enhanced security through authentication mechanisms. Let’s explore a typical Nginx configuration for secure authentication:</p>
<ul>
<li><strong>/verify_token</strong>: This block forwards authentication requests to a dedicated server. By excluding the request body and focusing on essential headers, it ensures that only valid, authenticated requests proceed.</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>conf</span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code class="language-conf" data-lang="conf">location = /verify_token {
    proxy_pass http://{your_auth_server}:2424;
    proxy_pass_request_body off;
    proxy_set_header Content-Length &#34;&#34;;
    proxy_set_header X-Original-URI $request_uri;
    proxy_set_header X-Original-Remote-Addr $remote_addr;
    proxy_set_header X-Original-Host $host;
}</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li><strong>/login</strong>: Catering to login requests, this configuration forwards the necessary details to the authentication server, preserving crucial information about the request&rsquo;s origin.</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>conf</span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code class="language-conf" data-lang="conf">location /login {
    proxy_pass http://{your_auth_server}:2424;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li><strong>Error Handling (@error401)</strong>: A clever redirect mechanism that guides unauthenticated users to the login page, keeping the original URL intact.</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>conf</span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code class="language-conf" data-lang="conf">location @error401 {
    return 302 {your_domain}/login;
}</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li><strong>Root Location (/)</strong>: The gateway to your service, which rigorously checks each request for authentication, granting access only to verified users.</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>conf</span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code class="language-conf" data-lang="conf">location / {
    auth_request /verify_token;
    error_page 401 = @error401;
    proxy_pass http://{your_server}:2323/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection &#39;upgrade&#39;;
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
}</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>This setup not only fortifies your service against unauthorized access but also maintains a seamless user experience, redirecting unauthenticated users without hassle.</p>
<h3 id="implementing-jwt-for-robust-backend-authentication">Implementing JWT for Robust Backend Authentication</h3>
<p>Implementing JWT (JSON Web Tokens) in a Flask web application provides a secure way of handling authentication. The provided Flask code demonstrates how JWT can be integrated for a robust backend authentication system:</p>
<ol>
<li><strong>Setup and Environment Variables</strong>:
<ul>
<li>The Flask app is configured with a secret key, essential for JWT encoding and decoding.</li>
</ul>
</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">os</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">dotenv</span> <span class="kn">import</span> <span class="n">load_dotenv</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">load_dotenv</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">app</span><span class="o">.</span><span class="n">secret_key</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s1">&#39;SECRET_KEY&#39;</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol>
<li><strong>Login Route</strong>:
<ul>
<li>The <code>/login</code> route handles user authentication. Upon successful login, a JWT is encoded with the user&rsquo;s information and expiration time, then sent as a cookie.</li>
</ul>
</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nd">@app.route</span><span class="p">(</span><span class="s1">&#39;/login&#39;</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;POST&#39;</span><span class="p">,</span> <span class="s1">&#39;GET&#39;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">login</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">count</span> <span class="o">=</span> <span class="n">update_visit_count</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span> <span class="o">==</span> <span class="s1">&#39;POST&#39;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">username</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s1">&#39;username&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="n">password</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s1">&#39;password&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># Validate credentials (use a secure method in production)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">username</span> <span class="o">==</span> <span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s1">&#39;chat_username&#39;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">password</span> <span class="o">==</span> <span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s1">&#39;password&#39;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">token</span> <span class="o">=</span> <span class="n">jwt</span><span class="o">.</span><span class="n">encode</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">                <span class="s1">&#39;user&#39;</span><span class="p">:</span> <span class="n">username</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s1">&#39;exp&#39;</span><span class="p">:</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">utcnow</span><span class="p">()</span> <span class="o">+</span> <span class="n">datetime</span><span class="o">.</span><span class="n">timedelta</span><span class="p">(</span><span class="n">minutes</span><span class="o">=</span><span class="mi">30</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="p">},</span> <span class="n">app</span><span class="o">.</span><span class="n">secret_key</span><span class="p">,</span> <span class="n">algorithm</span><span class="o">=</span><span class="s1">&#39;HS256&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="n">response</span> <span class="o">=</span> <span class="n">make_response</span><span class="p">(</span><span class="n">redirect</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">            <span class="n">response</span><span class="o">.</span><span class="n">set_cookie</span><span class="p">(</span><span class="s1">&#39;token&#39;</span><span class="p">,</span> <span class="n">token</span><span class="p">,</span> <span class="n">max_age</span><span class="o">=</span><span class="mi">1800</span><span class="p">)</span>  <span class="c1"># Keep login status for 30 mins</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">response</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="n">error</span> <span class="o">=</span> <span class="s1">&#39;Invalid credentials&#39;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s1">&#39;login.html&#39;</span><span class="p">,</span> <span class="n">error</span><span class="o">=</span><span class="n">error</span><span class="p">,</span> <span class="n">count</span><span class="o">=</span><span class="n">count</span><span class="p">),</span> <span class="mi">401</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1"># Show login page</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s1">&#39;login.html&#39;</span><span class="p">,</span><span class="n">count</span><span class="o">=</span><span class="n">count</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol>
<li><strong>Token Verification</strong>:
<ul>
<li>A decorator <code>token_required</code> is used to verify the JWT token in subsequent requests. This ensures that only authenticated users can access certain routes.</li>
</ul>
</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">token_required</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">decorator</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">token</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">cookies</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;token&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="ow">not</span> <span class="n">token</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;token is none&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="s1">&#39;/login&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">jwt</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="n">token</span><span class="p">,</span> <span class="n">app</span><span class="o">.</span><span class="n">secret_key</span><span class="p">,</span> <span class="n">algorithms</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;HS256&#39;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        <span class="k">except</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;token is invalid&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="s1">&#39;/login&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">f</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">decorator</span><span class="o">.</span><span class="vm">__name__</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="vm">__name__</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">decorator</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol>
<li><strong>Token Validation Endpoint</strong>:
<ul>
<li>The <code>/verify_token</code> endpoint checks the validity of the token, which is essential for integrating with the Nginx authentication mechanism.</li>
</ul>
</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nd">@app.route</span><span class="p">(</span><span class="s1">&#39;/verify_token&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">verify_token</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">token</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">cookies</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;token&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="ow">not</span> <span class="n">token</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s1">&#39;Access Denied&#39;</span><span class="p">,</span> <span class="mi">401</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">jwt</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="n">token</span><span class="p">,</span> <span class="n">app</span><span class="o">.</span><span class="n">secret_key</span><span class="p">,</span> <span class="n">algorithms</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;HS256&#39;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s1">&#39;Authorized&#39;</span><span class="p">,</span> <span class="mi">200</span>
</span></span><span class="line"><span class="cl">    <span class="k">except</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s1">&#39;Access Denied&#39;</span><span class="p">,</span> <span class="mi">401</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol>
<li><strong>Dynamic Secret Key Update</strong>:
<ul>
<li>A function <code>update_secret_key_in_env</code> is included to update the secret key daily, enhancing security by invalidating old tokens.</li>
</ul>
</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># Function to generate a new secret key and write it to the .env file</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">update_secret_key_in_env</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">env_file_path</span> <span class="o">=</span> <span class="s1">&#39;.env&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="n">secret_key</span> <span class="o">=</span> <span class="sa">f</span><span class="s1">&#39;SECRET_KEY=</span><span class="si">{</span><span class="n">secrets</span><span class="o">.</span><span class="n">token_urlsafe</span><span class="p">(</span><span class="mi">32</span><span class="p">)</span><span class="si">}</span><span class="s1">&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="n">last_updated</span> <span class="o">=</span> <span class="sa">f</span><span class="s1">&#39;LAST_UPDATED=</span><span class="si">{</span><span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">&#34;%Y-%m-</span><span class="si">%d</span><span class="s2">&#34;</span><span class="p">)</span><span class="si">}</span><span class="s1">&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="n">key_updated</span> <span class="o">=</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Check if .env file exists and read the content</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">env_file_path</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">env_file_path</span><span class="p">,</span> <span class="s1">&#39;r&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">file</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">lines</span> <span class="o">=</span> <span class="n">file</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># Update or add SECRET_KEY and LAST_UPDATED</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">line</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">lines</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="s1">&#39;LAST_UPDATED&#39;</span> <span class="ow">in</span> <span class="n">line</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="n">last_updated_date</span> <span class="o">=</span> <span class="n">line</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;=&#39;</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span> <span class="n">last_updated_date</span> <span class="o">!=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">&#34;%Y-%m-</span><span class="si">%d</span><span class="s2">&#34;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">                    <span class="n">lines</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">last_updated</span> <span class="o">+</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span>
</span></span><span class="line"><span class="cl">                    <span class="n">key_updated</span> <span class="o">=</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl">            <span class="k">elif</span> <span class="s1">&#39;SECRET_KEY&#39;</span> <span class="ow">in</span> <span class="n">line</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span> <span class="n">key_updated</span> <span class="ow">is</span> <span class="kc">True</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                    <span class="n">lines</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">secret_key</span> <span class="o">+</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span>
</span></span><span class="line"><span class="cl">                <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;no need to update the secret key today&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="n">key_updated</span> <span class="o">=</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># If SECRET_KEY or LAST_UPDATED are not found, add them</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="ow">not</span> <span class="n">key_updated</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">lines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">last_updated</span> <span class="o">+</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">lines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">secret_key</span> <span class="o">+</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">key_updated</span> <span class="o">=</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># Write back to .env file</span>
</span></span><span class="line"><span class="cl">        <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">env_file_path</span><span class="p">,</span> <span class="s1">&#39;w&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">file</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">file</span><span class="o">.</span><span class="n">writelines</span><span class="p">(</span><span class="n">lines</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">else</span><span class="p">:</span> <span class="c1"># If .env file doesn&#39;t exist, create one</span>
</span></span><span class="line"><span class="cl">        <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">env_file_path</span><span class="p">,</span> <span class="s1">&#39;w&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">file</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">file</span><span class="o">.</span><span class="n">writelines</span><span class="p">([</span><span class="n">last_updated</span> <span class="o">+</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">,</span> <span class="n">secret_key</span> <span class="o">+</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        <span class="n">key_updated</span> <span class="o">=</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">key_updated</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Secret key and last updated date added/updated in .env file.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;No update required for today.&#34;</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol>
<li><strong>Visitor Count Feature</strong>:
<ul>
<li>As part of the user experience, a visitor count is maintained, which is updated with each visit.</li>
</ul>
</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">update_visit_count</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&#34;visit_count.txt&#34;</span><span class="p">,</span> <span class="s2">&#34;r&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">file</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">count</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">file</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">        <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&#34;visit_count.txt&#34;</span><span class="p">,</span> <span class="s2">&#34;w&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">file</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">count</span> <span class="o">+=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">            <span class="n">file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">count</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">count</span>
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">IOError</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s2">&#34;Error&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>This implementation of JWT in a Flask application exemplifies a secure and efficient way of handling user authentication, ensuring that only authorized users can access protected services.</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240127161720.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240127161720.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240127161720.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="designing-a-user-friendly-frontend">Designing a User-Friendly Frontend</h3>
<p>In tandem with robust backend security, the frontend of your web service plays a crucial role in user engagement and satisfaction. Let&rsquo;s delve into the key features of our project&rsquo;s frontend design:</p>
<p><strong>Theme Toggle and Slogan</strong>:</p>
<ul>
<li>The theme switcher allows users to choose between dark and light modes.</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;theme-switch-wrapper&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">button</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;theme-toggle&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;theme-toggle&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;moon&#34;</span><span class="p">&gt;</span><span class="ni">&amp;#9790;</span><span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;sun&#34;</span><span class="p">&gt;</span><span class="ni">&amp;#9728;</span><span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>A catchy slogan is displayed, setting a creative and visionary tone.</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;slogan&#34;</span><span class="p">&gt;</span>Crafting Tomorrow&#39;s Narratives, Today.<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>Login Interface</strong>:
The entry point of any web service, the login page, is where security meets user experience. Our Flask-based web application presents a clean and intuitive login interface. It includes fields for username and password and a login button. This simplicity ensures ease of use while maintaining a professional appearance.</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">form</span> <span class="na">action</span><span class="o">=</span><span class="s">&#34;/login&#34;</span> <span class="na">method</span><span class="o">=</span><span class="s">&#34;post&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;email&#34;</span> <span class="na">placeholder</span><span class="o">=</span><span class="s">&#34;Username&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;username&#34;</span> <span class="na">required</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;password&#34;</span> <span class="na">placeholder</span><span class="o">=</span><span class="s">&#34;Password&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;password&#34;</span> <span class="na">required</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;submit&#34;</span><span class="p">&gt;</span>Login<span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>Additional subtitle for contextual information.</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;subtitle&#34;</span><span class="p">&gt;</span>If you want to reach this server, please contact Aiken or Metis.<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>Interactive Error Handling</strong>:</p>
<ul>
<li>A unique error message display using a cat image, adding a touch of humor.</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">{% if error %}
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;error-cat&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;{{ url_for(&#39;static&#39;, filename=&#39;images/cat.webp&#39;) }}&#34;</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;Cat&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;speech-bubble&#34;</span><span class="p">&gt;</span>{{ error }}<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">{% endif %}</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>Footer with Visitor Count</strong>:</p>
<ul>
<li>Displaying the visitor count adds an interactive and transparent element.</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    This page has been visited {{ count }} times.
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240127161058.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240127161058.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240127161058.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="comparing-authentication-methods-jwt-oauth-and-basic-authentication">Comparing Authentication Methods: JWT, OAuth, and Basic Authentication</h3>
<p>In the realm of web security, selecting the right authentication method is crucial. Let&rsquo;s compare JWT (JSON Web Tokens), OAuth, and Basic Authentication to understand their unique features and use cases:</p>
<ol>
<li>
<p><strong>JWT (JSON Web Tokens)</strong>:</p>
<ul>
<li><strong>Mechanism</strong>: Encoded tokens that carry claims and are used for secure data exchange.</li>
<li><strong>Use Cases</strong>: Ideal for single sign-on (SSO) and stateless applications.</li>
<li><strong>Pros</strong>: Highly flexible, supports cross-domain requests, and is self-contained with payload data.</li>
<li><strong>Cons</strong>: Requires careful management of secret keys and token expiration.</li>
</ul>
</li>
<li>
<p><strong>OAuth</strong>:</p>
<ul>
<li><strong>Mechanism</strong>: An authorization framework allowing applications to secure designated access without revealing user credentials.</li>
<li><strong>Use Cases</strong>: Best for third-party access (like social logins) and granting limited access to user data.</li>
<li><strong>Pros</strong>: Enhanced security as user credentials are not exposed, and allows token-based access control.</li>
<li><strong>Cons</strong>: Complex implementation and requires understanding of tokens and scopes.</li>
</ul>
</li>
<li>
<p><strong>Basic Authentication</strong>:</p>
<ul>
<li><strong>Mechanism</strong>: A simple authentication scheme built into the HTTP protocol using username and password.</li>
<li><strong>Use Cases</strong>: Suitable for simple login needs, especially when accessing APIs for internal use.</li>
<li><strong>Pros</strong>: Easy to implement and understand.</li>
<li><strong>Cons</strong>: Less secure as it sends credentials in base64 encoded format, vulnerable to interception.</li>
</ul>
</li>
</ol>
<p>Each of these methods has its strengths and weaknesses, and the choice largely depends on the specific requirements of your web application.</p>
<h3 id="conclusion-balancing-security-and-user-experience-in-web-services">Conclusion: Balancing Security and User Experience in Web Services</h3>
<p>As we conclude this journey through securing and personalizing web services, it&rsquo;s clear that the right blend of backend security and frontend design can significantly enhance both the security and user experience of a web application.</p>
<p>From implementing robust JWT authentication in a Flask application to designing an engaging and intuitive frontend, each aspect plays a pivotal role in delivering a seamless and secure user experience. Whether it&rsquo;s the compact and scalable nature of JWTs, the interactive and user-friendly design elements on the frontend, or the comparative analysis of different authentication methods, each component contributes to a comprehensive web service solution.</p>
<p>For small projects, especially, the choice of JWT stands out for its efficiency, scalability, and ease of implementation, making it a wise choice for developers looking to secure their applications without compromising on performance or user experience.</p>
<p>In the end, the key takeaway is that security and usability do not have to be at odds; with the right tools and approaches, they can complement each other to create web services that are not only secure but also enjoyable to use.</p>
<p>We encourage our readers to explore the code and concepts discussed in this blog post and to visit the GitHub repository for the original code at <a href="https://github.com/AikenH/ezEncryptYourService?tab=readme-ov-file" target="_blank" rel="noopener">ezEncryptYourService</a>
. Dive in, experiment, and elevate your web services to new heights of security and user engagement.</p>
]]></content:encoded>
    </item>
    <item>
      <title>家庭服务器的备份工具选择</title>
      <link>https://aikenh.cn/posts/backuptoolsforhomeserver/</link>
      <pubDate>Fri, 29 Dec 2023 08:04:06 +0000</pubDate>
      <guid>https://aikenh.cn/posts/backuptoolsforhomeserver/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-summary&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Summary&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;在搭建了 Immich 服务之后，考虑到数据本身的重要性，又对硬盘本身的寿命和各种数据安全的场景有所顾虑，对加密备份的需求就浮出水面了，希望能有一个备份的预案来对抗各种数据风险，因此有本篇文章，对各种备份工具做简单调研和选择。&lt;/p&gt;

&lt;/blockquote&gt;
&lt;p&gt;
&lt;div class=&#34;post-img-view&#34;&gt;
  &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231229113137.png&#34;&gt;
    &lt;img alt=&#34;image.png&#34; loading=&#34;lazy&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231229113137.png&#34;class=&#34;responsive-image&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231229113137.png&#34; style=&#34;display: block; margin: 0 auto;&#34;
      alt=&#34;image.png&#34;  /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;script&gt;
  document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
      var images = document.querySelectorAll(&#34;.responsive-image&#34;);
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + &#34;px&#34;;
      });
  });
&lt;/script&gt;
&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>在搭建了 Immich 服务之后，考虑到数据本身的重要性，又对硬盘本身的寿命和各种数据安全的场景有所顾虑，对加密备份的需求就浮出水面了，希望能有一个备份的预案来对抗各种数据风险，因此有本篇文章，对各种备份工具做简单调研和选择。</p>

</blockquote>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231229113137.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231229113137.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231229113137.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="intro-调研对象介绍">👾Intro 调研对象介绍</h2>
<p>👍出场选手介绍，节选来自以下网站的备份方案：<a href="https://github.com/awesome-foss/awesome-sysadmin#backups" target="_blank" rel="noopener">awesome-sysadmin-backup</a>
</p>
<ul>
<li><a href="https://kopia.io/" target="_blank" rel="noopener">kopia</a>
</li>
<li><a href="https://www.urbackup.org/" target="_blank" rel="noopener">urBackUp</a>
</li>
<li><a href="https://restic.net/" target="_blank" rel="noopener">restic</a>
</li>
<li><a href="https://rclone.org/" target="_blank" rel="noopener">rclone</a>
</li>
<li><a href="https://duplicity.gitlab.io/" target="_blank" rel="noopener">duplicity</a>
</li>
<li><a href="https://www.duplicati.com/" target="_blank" rel="noopener">Duplicati</a>
</li>
<li><a href="https://duplicacy.com/" target="_blank" rel="noopener">Duplicacy</a>
</li>
<li>脚本实现简单的备份和上传：Crontab+自动 tar 加密+Webdav 接口进行上传</li>
</ul>
<p>为了备份大量包含隐私的图像信息，这里最基础的需求有以下几点：<strong>加密</strong>，<strong>支持云端存储</strong>服务/Webdav，<strong>增量备份</strong>，<strong>免费</strong>；</p>
<p>额外如果能够支持以下的需求则额外加分：<strong>压缩</strong>，<strong>去重</strong>，<strong>平台一致性</strong>，<strong>用户界面友好</strong>（备份状态检查等）</p>
<h2 id="compare-特性对比">🏓Compare 特性对比</h2>
<table>
  <thead>
      <tr>
          <th>Name</th>
          <th>PSWD</th>
          <th>Zip</th>
          <th>Webdav</th>
          <th>Add</th>
          <th>Type</th>
          <th>ui</th>
          <th>Consis</th>
          <th>free</th>
          <th>rate</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>kopia</td>
          <td>y</td>
          <td>y</td>
          <td>y</td>
          <td>y</td>
          <td>Full</td>
          <td>y</td>
          <td>y</td>
          <td>y</td>
          <td>🔥🔥🔥🔥🔥</td>
      </tr>
      <tr>
          <td>urbackup</td>
          <td>y</td>
          <td>n</td>
          <td>n</td>
          <td>y</td>
          <td>C/S</td>
          <td>y</td>
          <td>y</td>
          <td>y</td>
          <td>🔥</td>
      </tr>
      <tr>
          <td>restic</td>
          <td>y</td>
          <td>n</td>
          <td>r/o</td>
          <td>y</td>
          <td>CLI</td>
          <td>n</td>
          <td>y</td>
          <td>y</td>
          <td>🔥</td>
      </tr>
      <tr>
          <td>duplicity</td>
          <td>y</td>
          <td>n</td>
          <td>y</td>
          <td>y</td>
          <td>CLI</td>
          <td>n</td>
          <td>n</td>
          <td>y</td>
          <td>🔥🔥</td>
      </tr>
      <tr>
          <td>duplicati</td>
          <td>y</td>
          <td>n</td>
          <td>y</td>
          <td>y</td>
          <td>Full</td>
          <td>y</td>
          <td>n</td>
          <td>y</td>
          <td>🔥🔥🔥🔥</td>
      </tr>
      <tr>
          <td>duplicacy</td>
          <td>y</td>
          <td>y</td>
          <td>y</td>
          <td>y</td>
          <td>Full</td>
          <td>y-</td>
          <td>y</td>
          <td>y-</td>
          <td>🔥🔥🔥🔥🔥</td>
      </tr>
  </tbody>
</table>
<blockquote>
<p>C/S: Client &amp; Server 的模式，在需要备份的机器上安装客户端，在存储备份的机器上安装服务端，通常用于 NAS 存储各个终端数据的场景，如<strong>urbackup</strong>。</p>
</blockquote>
<p>PSWD: Password 支持加密访问数据或者服务，保证数据的安全。
Add: Incremental 额外支持快速增量备份，能够识别出新增文件。
Consis: Consistent 备份数据一致性，多个平台保持一致的备份数据格式，以及数据恢复能力。
Webdav：是否支持云端存储服务？</p>
<ul>
<li>y 表示支持 Aliyun 或者 webdav 实现对国内网盘的支持。</li>
<li>o 表示支持 OSS 等对象存储服务。</li>
<li>n 表示只支持本地存储，可能需要通过脚本手动和云端存储进行交互（如果可以表示备份状态也可以）</li>
<li>r 表示支持 rclone 挂载的云端对象，rclone+alist 可以支持国内硬盘服务。</li>
</ul>



  
  

<blockquote class="alert-blockquote alert-udpate">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Udpate</span>
  </p>
  <p>update：I really need to find this before I Wrote This.
<a href="https://wiki.archlinux.org/title/Synchronization_and_backup_programs#Chunk-based_increments" target="_blank" rel="noopener">https://wiki.archlinux.org/title/Synchronization_and_backup_programs#Chunk-based_increments</a>
</p>

</blockquote>
<h3 id="features-具体特性">🍴Features 具体特性</h3>
<p><strong>Kopia</strong>: 用户界面友好，支持压缩，支持快照映射到本地，支持定时备份，支持 webdav，支持各种备份策略，支持网页版管理，支持加密，支持同时备份到多个目的地，高效，使用简单。</p>
<p>参考资料：<a href="https://zhuanlan.zhihu.com/p/541234817" target="_blank" rel="noopener">Kopia: 全平台开源备份软件新秀</a>
</p>
<p><strong>urbackup</strong>: 可以对整个系统进行完整的定时备份，主要用于重要的服务器的容灾备份，也可灵活备份某个文件夹，但对当前的需求来说并不是最合适的。</p>
<p><strong>restic</strong>: 命令行备份工具，支持备份到 OSS 或者 RClone 挂载的各种云端对象，通过快照的存储可以实现不同时间备份<strong>单文件</strong>的恢复，支持增量备份和完全备份，支持备份特定文件夹，支持 Docker 安装，目前看来可以通过 Rclone 和 Alist 的组合来彻底满足我们的需求，可能需要本地环境作中转。</p>
<p>参考资料：<a href="https://www.escapelife.site/posts/912084a4.html" target="_blank" rel="noopener">restic操作指令详解</a>
, <a href="https://juejin.cn/post/7014803100074672135" target="_blank" rel="noopener">restic介绍</a>
, <a href="https://zhuanlan.zhihu.com/p/381151432" target="_blank" rel="noopener">restic简介</a>
</p>
<p><strong>duplicity</strong>: 命令行备份工具，优势在于直接支持 Webdav，极其高效的增量备份，支持单个文件的恢复，支持指定日期的恢复，可使用 GPG 秘钥进行加密解密；缺点在于目前仅支持 Linux 环境，可能需要编写脚本来支持定时运行，可以基于 WSL2 实现对 Windows 本机的备份，但是带宽和 CPU 等要素相对受限，无法完全发挥性能。</p>
<blockquote>
<p>duplicity 有一个严重的缺陷在于其增量备份方法，每一次备份都需要用户选择是否全量备份或者增量备份，并且其设计决定了在一个备份了很多次的仓库中删除任何一个历史的备份变得不可能。</p>
</blockquote>
<p>参考资料：<a href="https://www.vinchin.com/blog/vinchin-technique-share-details.html?id=18434" target="_blank" rel="noopener">Linux全新的备份神器Duplicity</a>
</p>
<p><strong>duplicati</strong>：带 UI 的备份工具，支持备份到 Webdav，也支持命令行工具，支持 docker，支持增量备份，操作简单，支持计划备份和清除，支持 NGINX 部署访问，单文件恢复可能不支持，但支持选中单文件夹进行恢复，完美符合需求。</p>
<p>参考资料：<a href="https://nasdaddy.com/how-to-install-duplicati-on-your-nas/" target="_blank" rel="noopener">Duplicity备份到Alist</a>
，<a href="https://zhuanlan.zhihu.com/p/588678612" target="_blank" rel="noopener">Duplicity备份到COS</a>
，<a href="https://blognas.hwb0307.com/linux/docker/471" target="_blank" rel="noopener">Docker搭建Duplicati</a>
</p>
<p><strong>duplicacy</strong>：CLI 免费，付费提供网页管理界面，支持 webdav，增量备份，支持加密备份，使用 Lock-Free(参考资料 1) 技术来节省空间，不会无法删除快照，支持多个客户端备份到同一个云端存储，支持 docker 安装（可能需要<a href="https://duplicacy.com/buy.html" target="_blank" rel="noopener">许可证</a>
）</p>
<p>参考资料：<a href="https://einverne.github.io/post/2021/06/duplicacy-backup-tool-usage.html" target="_blank" rel="noopener">Duplicacy 增量备份工具使用</a>
，<a href="https://blog.csdn.net/wbsu2004/article/details/129459030" target="_blank" rel="noopener">Duplicacy Docker安装</a>
，<a href="https://www.moewah.com/archives/5292.html" target="_blank" rel="noopener">Duplicacy CLI使用</a>
</p>



  
  

<blockquote class="alert-blockquote alert-note">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Note</span>
  </p>
  <p>如果是存储各时段快照的版本，记得使用指定的命令删除过时的快照。</p>

</blockquote>
<h3 id="pick-最终选择">⛏️Pick 最终选择</h3>
<center>KOPIA</center>
<ul>
<li>duplicati 在<a href="https://www.reddit.com/r/selfhosted/comments/upbp99/kopia_vs_duplicati/" target="_blank" rel="noopener">查阅资料</a>
后提前出局，出现的 bug 等相对会多些</li>
<li>duplicacy 看起来十分美好，但是网页管理功能需要付费使用，虽然可以接受，但是当 kopia 有更好选择的时候就暂时被搁置了。</li>
</ul>
<p>如果后续使用中 kopia 没有 lock-free 的优势或者说在多次备份后需要保存大量快照且无法删除的硬伤，则不会再更新，如果发现 kopia 有所缺陷，则更新该部分内容。</p>
<p>参考资料：<a href="https://forum.duplicati.com/t/duplicati-vs-duplicacy-vs-kopia-vs-vorta/14493" target="_blank" rel="noopener">kopia-duplicati-duplicacy-vorta</a>
</p>
<h2 id="脚本组成分析">🦶脚本组成分析</h2>
<p>如果要做一个功能完备，但是简单的自用备份服务，个人认为应该包含以下的内容：</p>
<ul>
<li>定时任务：对定时脚本进行更改，执行和启用定时任务</li>
<li>文件加密：可以使用简单的打包命令进行加密打包，</li>
<li>文件传输：将备份文件传输至指定地方，包括 webdav 的上传，</li>
<li><strong>增量备份</strong>：无论是快照或者版本管理的思路，能够识别出新增内容并仅针对新增内容进行传输</li>
</ul>
<p>上述任务中无论是定时，还是文件压缩、传输、都有较为简单的基础方式，里面最复杂的且我认为是比较重要的则恰恰是增量备份这一点，这一点对备份的效率和空间占用都是十分关键的，不会使得每次备份都需要较多时间和性能成本。</p>
<ul>
<li><input disabled="" type="checkbox"> 这里有时间希望去学习一下上述开源项目，学习如何建立一个快照系统。</li>
</ul>
<h2 id="fi">🌻FI</h2>
]]></content:encoded>
    </item>
    <item>
      <title>搭建家庭服务器1 整体方案设计</title>
      <link>https://aikenh.cn/posts/%E5%AE%B6%E5%BA%AD%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%95%B4%E4%BD%93%E6%96%B9%E6%A1%88/</link>
      <pubDate>Wed, 20 Dec 2023 08:24:36 +0000</pubDate>
      <guid>https://aikenh.cn/posts/%E5%AE%B6%E5%BA%AD%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%95%B4%E4%BD%93%E6%96%B9%E6%A1%88/</guid>
      <description>&lt;head&gt;
    
    &lt;script src=&#34;https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/crypto-js/3.1.9-1/crypto-js.js&#34;&gt;&lt;/script&gt;
&lt;/head&gt;





&lt;div class=&#34;hugo-encryptor-container&#34;&gt;
  &lt;div class=&#34;hugo-encryptor-prompt&#34;&gt;
    
      &lt;p&gt;文章的部分内容被密码保护：&lt;/p&gt;
    
  &lt;/div&gt;
  &lt;div class=&#34;hugo-encryptor-form&#34;&gt;
    &lt;input
      class=&#34;hugo-encryptor-input&#34;
      placeholder=&#39;请输入密码&#39;
    /&gt;
    &lt;input
      class=&#34;hugo-encryptor-button&#34;
      type=&#34;button&#34;
      value=&#39;CLICK&#39;
      onclick=&#34;_click_handler(this)&#34;
    /&gt;
  &lt;/div&gt;
  &lt;div
    class=&#34;hugo-encryptor-cipher-text&#34;
    data-password=&#34;aikenhong_blog&#34;
    style=&#34;display: none;&#34;
  &gt;
    &lt;span style=&#34;display: none;&#34;&gt;--- DON&#39;T MODIFY THIS LINE ---&lt;/span&gt;
    


  
  

&lt;blockquote class=&#34;alert-blockquote alert-summary&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Summary&lt;/span&gt;
  &lt;/p&gt;</description>
      <content:encoded><![CDATA[<head>
    
    <script src="https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/crypto-js/3.1.9-1/crypto-js.js"></script>
</head>





<div class="hugo-encryptor-container">
  <div class="hugo-encryptor-prompt">
    
      <p>文章的部分内容被密码保护：</p>
    
  </div>
  <div class="hugo-encryptor-form">
    <input
      class="hugo-encryptor-input"
      placeholder='请输入密码'
    />
    <input
      class="hugo-encryptor-button"
      type="button"
      value='CLICK'
      onclick="_click_handler(this)"
    />
  </div>
  <div
    class="hugo-encryptor-cipher-text"
    data-password="aikenhong_blog"
    style="display: none;"
  >
    <span style="display: none;">--- DON'T MODIFY THIS LINE ---</span>
    


  
  

<blockquote class="alert-blockquote alert-summary">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Summary</span>
  </p>
  <p>本文主要介绍笔者的家庭服务器设计方案 V1。该方案中中涵盖影视、图像、图书&amp;文献、博客、智能家居管理、密码管理服务，以及公网上内容分发的初步设计和选择的考量。</p>

</blockquote>
<h2 id="整体架构">整体架构</h2>
<p>整个服务中心在设计的时候主要考虑以下的几个方面：</p>
<ul>
<li>💻操作设备&amp;系统(OS)和内容存储方案：如何<strong>经济实惠</strong>的选择合适的设备和系统</li>
<li>🌦️服务需求：需要搭建<strong>哪些服务</strong>，应该选择<strong>哪个服务</strong>进行自托管</li>
<li>🌍部署方案：如何保证在局域网+<strong>公网</strong>都能顺利且<strong>安全的访问</strong></li>
<li>📱访问策略：各个平台上的访问方式的选择</li>
</ul>
<p>此外，并非所有服务都需要在公网上进行部署，这里的部分服务可以仅用于局域网，由于仅开放了 Nginx 端口，因此从公网中访问不到未分发的内容，因此，部分存储与敏感信息相关的服务可以仅保留在局域网中进行访问。</p>



  
  

<blockquote class="alert-blockquote alert-note">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Note</span>
  </p>
  <p>在这种情况下如果希望能够使用一致的域名访问方式，是否可以考虑使用 Nginx 鉴权限制访问 ip 为内网 ip，其他公网访问直接丢弃？</p>

</blockquote>
<p>初版家庭服务中心的架构图如下，(这里并非列出所有的服务组件)，该架构图中所有的应用都是为了方便日常生活中的各项活动，下面会对架构图自底向上的做一些简单的说明。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231209082421.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231209082421.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231209082421.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="设备和存储选择">设备和存储选择</h3>
<p>存储和设备的选择主要来自以下的两个需求，首先是能够用作<strong>机顶盒</strong>，其次是尽量<strong>能省则省</strong>，综合考虑上述的两个需求，树莓派+网络云盘的策略有如下的几个优势，也是选择它的原因：</p>
<ul>
<li>设备和存储价格相对便宜，长时间在线电费消耗也几乎可以忽略不计</li>
<li>体积较小，作为机顶盒放置的方式较为简单</li>
<li>云盘的转存和资源收集的速度快，且可结合小雅和 Alist 进行网盘的集成，以及线上资源的整合。</li>
</ul>
<p>劣势就在于非本地存储和对网络的要求相对较高一些，且在系统上需要折腾的时间会比成熟的 NAS 厂家的开箱即用要折腾一些，最后就是一些对性能要求较高的服务树莓派可能无法承担这个职责，因此这里使用自己的个人电脑用来部署一些对性能要求较高的服务。</p>
<h3 id="服务部署策略">服务部署策略</h3>
<p>docker 在服务部署的优势有：独立互不影响的环境和一键部署方便性，因此我们使用 docker 进行几乎所有的服务的部署，并使用 portainer 对其进行管理。</p>
<ul>
<li>图书&amp;漫画：使用 Kavita+Calibre（进行资源的转换和元信息的不全）+ （Zlibray&amp;漫自由）获取资源。</li>
<li>照片：使用 Immich 满足整个家庭备份手机照片并进行统一管理的需求，可完全代替 icloud 且只需要本地磁盘。</li>
<li>影视：使用 Alist 整合自己的网盘 + 线上的 xiaoya 的 alist 资源 + emby 做一个影视墙（可选）+ Kodi 进行电视端的播放（KORE，kodi 手机端的官方遥控器）</li>
<li>智能家居：使用 HomeAssistant 管理各种不同品牌的智能家居设备</li>
</ul>
<h3 id="服务分发和服务访问">服务分发和服务访问</h3>
<p>这里使用 Nginx+腾讯云进行服务的分发，并通过 DDNSgo 动态更新域名解析的 IPV6 地址，之后就可以通过域名对相应服务进行访问。</p>
<blockquote>
<p>可用 Caddy 这个现在的后期之秀来代替 Nginx，Nginx 也可以安装对应的可视化设置界面。</p>
</blockquote>
<p>上述提到的是基于 ipv6 部署到公网后的分发情况，如果没有或者不想部署公网的话就使用如 Zerotier 和 Tailscale 的内网穿透服务来实现虚拟内网 ip+端口去访问服务。</p>
<p>在各个终端上的服务访问可以通过浏览器的<strong>保存为应用</strong>/<strong>固定到桌面</strong>，以及各自对应的官方 APP 为主要的访问手段。</p>
<h2 id="后续计划">后续计划</h2>



  
  

<blockquote class="alert-blockquote alert-note">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Note</span>
  </p>
  <p>这里记录后续希望进行补充的服务和设计，最终希望能够作为一个比较全面且完整的方案，覆盖到生活的方方面面，为自己和朋友的生活提供便利。</p>

</blockquote>
<ul>
<li><input checked="" disabled="" type="checkbox"> 设计 StableDiffusionWEBui 的<strong>鉴权</strong>页面，方便部署到公网上使用，方便作图需求</li>
<li><input checked="" disabled="" type="checkbox"> 现已涵盖视频图片和图书等服务，后续考虑是否有必要针对<strong>音乐</strong>添加相关页面</li>
<li><input checked="" disabled="" type="checkbox"> (eval) 菜谱管理中心，收藏各个不同的平台的菜谱</li>
<li><input checked="" disabled="" type="checkbox"> (eval) RSS Center 可能需要 RSS-HUB 创建自己关心的所有 RSS 源，然后通过</li>
<li><input checked="" disabled="" type="checkbox"> (eval) 使用 Ghost 尝试更新自己的 Blog</li>
<li><input checked="" disabled="" type="checkbox"> (eval) 更新 Homepage</li>
<li><input checked="" disabled="" type="checkbox"> 更新 CodeServer，是否要在网页上部署Vscode</li>
</ul>
<h2 id="fi">FI</h2>

  </div>
</div>

<script>
    


function sanitizeContent(content) {
    
    return content.replace(/[\x00-\x1F\x7F]/g, '').trim(); 
}

function encryptContent(password, content) {
    const key = CryptoJS.MD5(password).toString();
    const iv = key.substring(16); 
    const paddedContent = padContent(content);
    const encrypted = CryptoJS.AES.encrypt(paddedContent, CryptoJS.enc.Utf8.parse(key), {
        iv: CryptoJS.enc.Utf8.parse(iv),
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
}

function padContent(content) {
    const blockSize = 32; 
    const padlen = blockSize - (content.length % blockSize);
    
    
    return content;
}

function processEncryptedBlocks() {
    const blocks = document.querySelectorAll('.hugo-encryptor-cipher-text');
    blocks.forEach(block => {
        const password = block.getAttribute('data-password');
        const content = block.innerHTML.trim(); 
        const sanitizedContent = sanitizeContent(content); 
        const encryptedContent = encryptContent(password, sanitizedContent);
        block.innerHTML = encryptedContent;
        block.removeAttribute('data-password');
    });

    
    const script = document.createElement('script');
    script.src = '/js/decrypt.js';
    document.body.appendChild(script);
}


document.addEventListener('DOMContentLoaded', processEncryptedBlocks);
</script>
]]></content:encoded>
    </item>
    <item>
      <title>树莓派家庭影音中心2</title>
      <link>https://aikenh.cn/posts/%E6%A0%91%E8%8E%93%E6%B4%BE%E5%AE%B6%E5%BA%AD%E5%BD%B1%E9%9F%B3%E4%B8%AD%E5%BF%832/</link>
      <pubDate>Sat, 11 Nov 2023 12:08:37 +0000</pubDate>
      <guid>https://aikenh.cn/posts/%E6%A0%91%E8%8E%93%E6%B4%BE%E5%AE%B6%E5%BA%AD%E5%BD%B1%E9%9F%B3%E4%B8%AD%E5%BF%832/</guid>
      <description>&lt;h2 id=&#34;禁止屏幕休眠显示作为-dashboard-显示&#34;&gt;禁止屏幕休眠显示作为 Dashboard 显示&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;树莓派官方的 Raspbian 系统使用的是 lightdm 桌面显示管理器，可以设置 xservice 桌面交互显示来达到屏幕常亮的目的，也就是修改桌面配置文件 lightdm.Conf&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;参考资料：&lt;a href=&#34;http://www.raspi.cc/read-10-1.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;树莓派设置禁止让屏幕休眠，显示器保持常亮状态-树莓派基础学习入门-树莓派极客,raspi.cc - Powered by raspi&lt;/a&gt;
&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;div class=&#34;code-title&#34; onclick=&#34;toggleCode(this)&#34;&gt;
        
        &lt;span class=&#34;code-block-open&#34;&gt;&lt;ion-icon name=&#34;chevron-down-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/span&gt;
        &lt;span class=&#34;code-block-close&#34;&gt;&lt;ion-icon name=&#34;chevron-forward-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/ion-icon&gt;&lt;/span&gt;
        &lt;span&gt;shell&lt;/span&gt;
    &lt;/div&gt;
    &lt;div class=&#34;code-content&#34;&gt;
        
        &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo vim /etc/lightdm/lightdm.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === &#34;none&#34; || codeContent.style.display === &#34;&#34;) {
        codeContent.style.display = &#34;block&#34;; 
        codeContent.parentNode.classList.remove(&#34;code-has-hidden-child&#34;);
    } else {
        codeContent.style.display = &#34;none&#34;; 
        codeContent.parentNode.classList.add(&#34;code-has-hidden-child&#34;);
    }
}
&lt;/script&gt;&lt;p&gt;找到 x-server-command 取消注释并在后面加 &lt;code&gt;-s 0-dpms&lt;/code&gt;，添加完后重启即可。&lt;/p&gt;
&lt;p&gt;
&lt;div class=&#34;post-img-view&#34;&gt;
  &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231111132731.png&#34;&gt;
    &lt;img alt=&#34;image.png&#34; loading=&#34;lazy&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231111132731.png&#34;class=&#34;responsive-image&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231111132731.png&#34; style=&#34;display: block; margin: 0 auto;&#34;
      alt=&#34;image.png&#34;  /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;script&gt;
  document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
      var images = document.querySelectorAll(&#34;.responsive-image&#34;);
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + &#34;px&#34;;
      });
  });
&lt;/script&gt;
&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h2 id="禁止屏幕休眠显示作为-dashboard-显示">禁止屏幕休眠显示作为 Dashboard 显示</h2>
<blockquote>
<p>树莓派官方的 Raspbian 系统使用的是 lightdm 桌面显示管理器，可以设置 xservice 桌面交互显示来达到屏幕常亮的目的，也就是修改桌面配置文件 lightdm.Conf</p>
</blockquote>
<p>参考资料：<a href="http://www.raspi.cc/read-10-1.html" target="_blank" rel="noopener">树莓派设置禁止让屏幕休眠，显示器保持常亮状态-树莓派基础学习入门-树莓派极客,raspi.cc - Powered by raspi</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo vim /etc/lightdm/lightdm.conf</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>找到 x-server-command 取消注释并在后面加 <code>-s 0-dpms</code>，添加完后重启即可。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231111132731.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231111132731.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231111132731.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<blockquote>
<p>参数里的：-s 参数：设置屏幕保护不启动，0 数字零，-dpms 参数：关闭电源节能管理。</p>
</blockquote>
<h2 id="missing-x-server-or-display-无法启动问题">Missing X server or $DISPLAY 无法启动问题</h2>
<blockquote>
<p>在使用命令行等操作启动 GUI 应用的时候需要为其设定一个显示器，否则会报显示设备设置错误或不存在等问题导致其无法启动。</p>
</blockquote>
<p>参考资料：</p>
<ul>
<li><a href="https://blog.csdn.net/qq_43514711/article/details/125205605" target="_blank" rel="noopener">Kali Linux安装Google Chrome小记 野马菲比的博客</a>
</li>
<li><a href="https://www.itcodingman.com/no_x11_display_error/" target="_blank" rel="noopener">“无X11显示”相关错误含义和解决 - IT Coding Man</a>
</li>
</ul>
<p>通常 DISPLAY 会自己设置，但是使用远程的一些情况下该参数可能会有缺省的情况，在这种情况下需要我们手动设置一下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">DISPLAY</span><span class="o">=</span>:0.0</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>就可以启动 Gui 界面，例如启动 chrome</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">nohup chromium-browser --kiosk http://192.168.31.108:8123 <span class="p">&amp;;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>其中 <code>--kiosk</code> 参数代表全屏显示；</p>
<h2 id="kodi-关闭后黑屏重启-xorg">Kodi 关闭后黑屏/重启 Xorg</h2>
<p>树莓派 kodi 关闭以后经常显示器会处于一个黑屏的状态，如何使其正常的显示内容，也可以是说是图像界面卡死的解决办法；</p>
<p>参考资料：<a href="https://www.ancii.com/abdvxdd7p/" target="_blank" rel="noopener">树莓派图形界面卡死时的处理_安科网 (ancii.com)</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">ps -ef <span class="p">|</span> grep Xorg 
</span></span><span class="line"><span class="cl"><span class="c1"># 获取PID</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231111141037.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231111141037.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231111141037.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo <span class="nb">kill</span> -15 「PID」</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>即可实现自己重启 Xorg，归根结底，就是重启了 X 服务，因为 raspberry 默认用的是 lightdm 作为 X 服务的管理器，所以也可直接重启 lightdm。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo service lightdm restart</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="sudo-无需输入密码">Sudo 无需输入密码</h2>
<blockquote>
<p>该章节主要是为了后续用 ios 执行快捷方式的时候无需输入密码即可使用 sudo 指令，如果不这样做大部分的操作可能都无法执行。</p>
</blockquote>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># 下面两种选择一种进入编辑相关配置文件</span>
</span></span><span class="line"><span class="cl">sudo visudo
</span></span><span class="line"><span class="cl">sudo vim /etc/sudoers</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在 <code>%sudo </code> 下面新增一行添加自己的用户名。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">{user}   ALL=(ALL) NOPASSWD:ALL</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231111142713.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231111142713.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231111142713.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>参考资料：<a href="https://bingozb.github.io/views/default/58.html#%E5%90%8E%E8%AF%9D" target="_blank" rel="noopener">让Linux用户sudo操作免密码 | Bingo&rsquo;s Blog (bingozb.github.io)</a>
</p>
<h2 id="ios-使用快捷方式控制树莓派kodi和浏览器切换">ios 使用快捷方式控制树莓派Kodi和浏览器切换</h2>
<p>之所以介绍上面那些操作，实际上都是为了实现下面的切换脚本，这里使用快捷方式中的 SSH 来链接并执行 bash 指令，代码片段可以参考如下：</p>
<p>打开 kodi：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">nohup kodi <span class="p">&amp;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>切换 Dashboard，主要由以下的几个操作组成：关闭 Kodi，刷新 Xorg 显示界面，启动 Chrome 特定界面：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="k">for</span> pid in <span class="k">$(</span>ps -ef <span class="p">|</span> grep kodi <span class="p">|</span> awk <span class="s1">&#39;{print $2}&#39;</span><span class="k">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">do</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="nb">kill</span> -15 <span class="nv">$pid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">done</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1">#for pid in $( ps -ef | grep   &#39;Xorg&#39; |awk &#39;{print $2}&#39;);</span>
</span></span><span class="line"><span class="cl"><span class="c1">#do;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#sudo kill -15 $pid</span>
</span></span><span class="line"><span class="cl"><span class="c1">#done;</span>
</span></span><span class="line"><span class="cl">sudo service lightdm restart<span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">DISPLAY</span><span class="o">=</span>:0.0<span class="p">;</span>
</span></span><span class="line"><span class="cl">sleep <span class="m">10</span>
</span></span><span class="line"><span class="cl">nohup chromium-browser --kiosk http://&lt;Domain&gt;:&lt;port&gt; <span class="p">&amp;;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>快捷方式使用的方法也很简单，找到 SSH 运行脚本，填入主机端口用户密码，然后将上面的代码片段填入即可，这里建议分成三个脚本来使用会比较清晰一点。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231111145114.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231111145114.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231111145114.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="fi">FI</h2>
]]></content:encoded>
    </item>
    <item>
      <title>破解本地自托管Emby服务</title>
      <link>https://aikenh.cn/posts/emby_localhost_crack_by_nginx/</link>
      <pubDate>Fri, 10 Nov 2023 14:05:15 +0000</pubDate>
      <guid>https://aikenh.cn/posts/emby_localhost_crack_by_nginx/</guid>
      <description>&lt;h2 id=&#34;intro-问题描述&#34;&gt;Intro 问题描述&lt;/h2&gt;
&lt;p&gt;以 emby 为例，学习如何对这种自托管的服务，请求验证网站的软件进行破解，破解的整体思路分为以下的两类：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;一种是改客户端，一种是改服务端。两种方式的最终原理一样，都是搭建仿冒认证服务器，客户端访问伪服务器拿到授权信息；【3】&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;因此无论是那种方法我们都需要搭建伪验证服务器：所以以下的操作是必须的：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;抓取定位到验证服务器的地址，并获取验证服务器返回的验证信息格式；&lt;/li&gt;
&lt;li&gt;使用 Nginx 搭建虚拟的验证服务器，使其返回激活/验证信息；&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果是&lt;strong&gt;修改客户端&lt;/strong&gt;，则在搭建完验证站后需要：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;修改 Host 文件，将请求验证服务器的请求劫持到本地搭建的服务上；&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;修改服务端源文件，将默认的认证服务器 mb3admin.com 地址直接改成伪服务器&lt;/li&gt;
&lt;li&gt;这样就&lt;strong&gt;不需要安装自签名证书&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果是使用 Docker 进行部署的 emby 可以使用别人修改好的服务端的镜像进行部署安装（like 开心版）&lt;/p&gt;
&lt;p&gt;本文主要介绍验证服务器的搭建、修改客户端的方法，以及一些其他的注意事项；&lt;/p&gt;
&lt;h2 id=&#34;server-伪验证服务器搭建&#34;&gt;Server 伪验证服务器搭建&lt;/h2&gt;
&lt;h3 id=&#34;ca-证书申请&#34;&gt;CA 证书申请&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;什么是证书：&lt;a href=&#34;https://aws.amazon.com/cn/what-is/ssl-certificate/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;什么是 SSL 认证？- SSL/TLS 认证简介 - AWS (amazon.com)&lt;/a&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这里由于我们并没有真正拥有认证网站 md3admin 的域名故而没有对应的证书文件，因此需要为自己的服务自签发一个假的证书文件，并手动让浏览器信任该证书，保证在将该域名通过 hosts 修改转移到自己的服务上时，浏览器能正常请求该页面。&lt;/p&gt;
&lt;p&gt;下面介绍证书的签发过程（转载自参考文献:【2】)：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;div class=&#34;code-title&#34; onclick=&#34;toggleCode(this)&#34;&gt;
        
        &lt;span class=&#34;code-block-open&#34;&gt;&lt;ion-icon name=&#34;chevron-down-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/span&gt;
        &lt;span class=&#34;code-block-close&#34;&gt;&lt;ion-icon name=&#34;chevron-forward-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/ion-icon&gt;&lt;/span&gt;
        &lt;span&gt;shell&lt;/span&gt;
    &lt;/div&gt;
    &lt;div class=&#34;code-content&#34;&gt;
        
        &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir -p &amp;lt;username&amp;gt;/&amp;lt;docker-file-path&amp;gt;/nginx/cert/mb3admin.com &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; &amp;lt;username&amp;gt;/&amp;lt;docker-file-path&amp;gt;/nginx/cert/mb3admin.com
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 生成 CA 密钥&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;openssl genrsa -out ca.key &lt;span class=&#34;m&#34;&gt;2048&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 生成 CA 证书&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;openssl req -x509 -new -nodes -key ca.key -subj &lt;span class=&#34;s2&#34;&gt;&amp;#34;/C=CN/ST=Beijing/L=Beijing/O=&amp;lt;username&amp;gt;/OU=&amp;lt;username&amp;gt;/CN=&amp;lt;username&amp;gt;/emailAddress=&amp;lt;user-email&amp;gt;&amp;#34;&lt;/span&gt; -days &lt;span class=&#34;m&#34;&gt;36500&lt;/span&gt; -out ca.crt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 将 CA 转换成 p12 格式，并指定密码 （&amp;lt;username&amp;gt;）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;openssl pkcs12 -export -clcerts -in ./ca.crt -inkey ca.key -out ca.p12 -password pass:&amp;lt;username&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 将 p12 格式的证书 Base64 编码&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;base64 ca.p12
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Base64 一行不能超过 76 字符，超过则添加回车换行符。如果因为换行的原因，不能安装证书，可以使用 -w 参数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;base64 -w &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ca.p12
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 将 CA 转换成 pem 格式&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;openssl x509 -outform pem -in ca.crt -out ca.pem
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 生成服务端私钥 server.key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;openssl genrsa -out server.key &lt;span class=&#34;m&#34;&gt;2048&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 生成服务端证书请求 server.csr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;openssl req -new -sha256 -key server.key -out server.csr -subj &lt;span class=&#34;s2&#34;&gt;&amp;#34;/C=CN/L=Beijing/O=&amp;lt;username&amp;gt;/OU=&amp;lt;username&amp;gt;/CN=mb3admin.com/CN=*.mb3admin.com&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 生成服务端证书 server.crt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;openssl x509 -req -extfile &amp;lt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;printf&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;subjectAltName=DNS:mb3admin.com,DNS:*.mb3admin.com&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; -days &lt;span class=&#34;m&#34;&gt;3650&lt;/span&gt; -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === &#34;none&#34; || codeContent.style.display === &#34;&#34;) {
        codeContent.style.display = &#34;block&#34;; 
        codeContent.parentNode.classList.remove(&#34;code-has-hidden-child&#34;);
    } else {
        codeContent.style.display = &#34;none&#34;; 
        codeContent.parentNode.classList.add(&#34;code-has-hidden-child&#34;);
    }
}
&lt;/script&gt;&lt;p&gt;上述代码中替换一下自己的相关信息即可（也可以直接去参考资源中获取直接执行的代码）：&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h2 id="intro-问题描述">Intro 问题描述</h2>
<p>以 emby 为例，学习如何对这种自托管的服务，请求验证网站的软件进行破解，破解的整体思路分为以下的两类：</p>
<blockquote>
<p>一种是改客户端，一种是改服务端。两种方式的最终原理一样，都是搭建仿冒认证服务器，客户端访问伪服务器拿到授权信息；【3】</p>
</blockquote>
<p>因此无论是那种方法我们都需要搭建伪验证服务器：所以以下的操作是必须的：</p>
<ol>
<li>抓取定位到验证服务器的地址，并获取验证服务器返回的验证信息格式；</li>
<li>使用 Nginx 搭建虚拟的验证服务器，使其返回激活/验证信息；</li>
</ol>
<p>如果是<strong>修改客户端</strong>，则在搭建完验证站后需要：</p>
<ul>
<li>修改 Host 文件，将请求验证服务器的请求劫持到本地搭建的服务上；</li>
<li>需要伪服务器和客户端都要安装自签名证书</li>
</ul>
<p>如果是<strong>修改服务端</strong>，则后续需要：</p>
<ul>
<li>修改服务端源文件，将默认的认证服务器 mb3admin.com 地址直接改成伪服务器</li>
<li>这样就<strong>不需要安装自签名证书</strong></li>
</ul>
<p>如果是使用 Docker 进行部署的 emby 可以使用别人修改好的服务端的镜像进行部署安装（like 开心版）</p>
<p>本文主要介绍验证服务器的搭建、修改客户端的方法，以及一些其他的注意事项；</p>
<h2 id="server-伪验证服务器搭建">Server 伪验证服务器搭建</h2>
<h3 id="ca-证书申请">CA 证书申请</h3>
<blockquote>
<p>什么是证书：<a href="https://aws.amazon.com/cn/what-is/ssl-certificate/" target="_blank" rel="noopener">什么是 SSL 认证？- SSL/TLS 认证简介 - AWS (amazon.com)</a>
</p>
</blockquote>
<p>这里由于我们并没有真正拥有认证网站 md3admin 的域名故而没有对应的证书文件，因此需要为自己的服务自签发一个假的证书文件，并手动让浏览器信任该证书，保证在将该域名通过 hosts 修改转移到自己的服务上时，浏览器能正常请求该页面。</p>
<p>下面介绍证书的签发过程（转载自参考文献:【2】)：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">mkdir -p &lt;username&gt;/&lt;docker-file-path&gt;/nginx/cert/mb3admin.com <span class="o">&amp;&amp;</span> <span class="nb">cd</span> &lt;username&gt;/&lt;docker-file-path&gt;/nginx/cert/mb3admin.com
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 生成 CA 密钥</span>
</span></span><span class="line"><span class="cl">openssl genrsa -out ca.key <span class="m">2048</span> 
</span></span><span class="line"><span class="cl"><span class="c1"># 生成 CA 证书</span>
</span></span><span class="line"><span class="cl">openssl req -x509 -new -nodes -key ca.key -subj <span class="s2">&#34;/C=CN/ST=Beijing/L=Beijing/O=&lt;username&gt;/OU=&lt;username&gt;/CN=&lt;username&gt;/emailAddress=&lt;user-email&gt;&#34;</span> -days <span class="m">36500</span> -out ca.crt
</span></span><span class="line"><span class="cl"><span class="c1"># 将 CA 转换成 p12 格式，并指定密码 （&lt;username&gt;）</span>
</span></span><span class="line"><span class="cl">openssl pkcs12 -export -clcerts -in ./ca.crt -inkey ca.key -out ca.p12 -password pass:&lt;username&gt;
</span></span><span class="line"><span class="cl"><span class="c1"># 将 p12 格式的证书 Base64 编码</span>
</span></span><span class="line"><span class="cl">base64 ca.p12
</span></span><span class="line"><span class="cl"><span class="c1"># Base64 一行不能超过 76 字符，超过则添加回车换行符。如果因为换行的原因，不能安装证书，可以使用 -w 参数</span>
</span></span><span class="line"><span class="cl">base64 -w <span class="m">0</span> ca.p12
</span></span><span class="line"><span class="cl"><span class="c1"># 将 CA 转换成 pem 格式</span>
</span></span><span class="line"><span class="cl">openssl x509 -outform pem -in ca.crt -out ca.pem
</span></span><span class="line"><span class="cl"><span class="c1"># 生成服务端私钥 server.key</span>
</span></span><span class="line"><span class="cl">openssl genrsa -out server.key <span class="m">2048</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 生成服务端证书请求 server.csr</span>
</span></span><span class="line"><span class="cl">openssl req -new -sha256 -key server.key -out server.csr -subj <span class="s2">&#34;/C=CN/L=Beijing/O=&lt;username&gt;/OU=&lt;username&gt;/CN=mb3admin.com/CN=*.mb3admin.com&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 生成服务端证书 server.crt</span>
</span></span><span class="line"><span class="cl">openssl x509 -req -extfile &lt;<span class="o">(</span><span class="nb">printf</span> <span class="s2">&#34;subjectAltName=DNS:mb3admin.com,DNS:*.mb3admin.com&#34;</span><span class="o">)</span> -days <span class="m">3650</span> -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>上述代码中替换一下自己的相关信息即可（也可以直接去参考资源中获取直接执行的代码）：</p>
<ul>
<li><code>\&lt;username\&gt;</code></li>
<li><code>\&lt;user-email\&gt;</code></li>
<li><code>\&lt;docker-file-path\&gt;</code></li>
</ul>
<p>生成对应证书后，对证书的操作还有以下的两步，我们首先介绍证书安装，在对 Nginx 进行配置。</p>
<ul>
<li>Nginx 配置：将 server.crt 和 server.key 放到 nginx 存放的地方，方便后面配置 Nginx</li>
<li>证书安装：便于浏览器后续正常访问</li>
</ul>
<h3 id="证书安装">证书安装</h3>
<p>双击打开证书目录中的 crt 进行证书安装，会显示“无法验证到一个受信任的证书颁发机构”，这是因为我们只是自签发并没有找第三方机构认证，不要紧直接安装即可。</p>
<blockquote>
<p>没有安装证书的情况下也可能会发现验证信息正确但是激活失败的情况</p>
</blockquote>
<p>这里简单介绍以下 ubuntu 信任证书的方法【2】（nas 和 ios 可参考该文）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo cp ca.crt /usr/local/share/ca-certificates/zhuangzhuang.crt <span class="o">&amp;&amp;</span> sudo update-ca-certificates</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="nginx-设置">Nginx 设置</h3>
<p>Nginx 可以直接在 conf.d/default.conf 中新增以下代码片段</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>json</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="err">server</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="err">listen</span> <span class="err">443</span> <span class="err">ssl;</span>
</span></span><span class="line"><span class="cl">    <span class="err">listen</span> <span class="err">[::]:443</span> <span class="err">ssl;</span>
</span></span><span class="line"><span class="cl">    <span class="err">server_name</span> <span class="err">mb3admin.com;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="err">ssl_certificate</span> <span class="err">/etc/nginx/cert/mb3admin.com/server.crt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">ssl_certificate_key</span> <span class="err">/etc/nginx/cert/mb3admin.com/server.key;</span>
</span></span><span class="line"><span class="cl">	<span class="err">ssl_session_timeout</span> <span class="err">5m;</span>
</span></span><span class="line"><span class="cl">    <span class="err">ssl_protocols</span> <span class="err">TLSv1</span> <span class="err">TLSv1.1</span> <span class="err">TLSv1.2;</span>
</span></span><span class="line"><span class="cl">    <span class="err">ssl_ciphers</span> <span class="err">ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;</span>
</span></span><span class="line"><span class="cl">    <span class="err">ssl_prefer_server_ciphers</span> <span class="err">on;</span>
</span></span><span class="line"><span class="cl">    <span class="err">add_header</span> <span class="err">Access-Control-Allow-Origin</span> <span class="err">*;</span>
</span></span><span class="line"><span class="cl">    <span class="err">add_header</span> <span class="err">Access-Control-Allow-Headers</span> <span class="err">*;</span>
</span></span><span class="line"><span class="cl">    <span class="err">add_header</span> <span class="err">Access-Control-Allow-Method</span> <span class="err">*;</span>
</span></span><span class="line"><span class="cl">    <span class="err">add_header</span> <span class="err">Access-Control-Allow-Credentials</span> <span class="err">true;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="err">location</span> <span class="err">/admin/service/registration/validateDevice</span> <span class="err">{</span>
</span></span><span class="line"><span class="cl">        <span class="err">default_type</span> <span class="err">application/json;</span>
</span></span><span class="line"><span class="cl">        <span class="err">return</span> <span class="err">200</span> <span class="err">&#39;{</span><span class="nt">&#34;cacheExpirationDays&#34;</span><span class="p">:</span> <span class="mi">365</span><span class="p">,</span><span class="nt">&#34;message&#34;</span><span class="p">:</span> <span class="s2">&#34;Device Valid&#34;</span><span class="p">,</span><span class="nt">&#34;resultCode&#34;</span><span class="p">:</span> <span class="s2">&#34;GOOD&#34;</span><span class="p">}</span><span class="err">&#39;;</span>
</span></span><span class="line"><span class="cl">    <span class="err">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="err">location</span> <span class="err">/admin/service/registration/validate</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="err">default_type</span> <span class="err">application/json;</span>
</span></span><span class="line"><span class="cl">        <span class="err">return</span> <span class="err">200</span> <span class="err">&#39;{</span><span class="nt">&#34;featId&#34;</span><span class="p">:</span><span class="s2">&#34;&#34;</span><span class="p">,</span><span class="nt">&#34;registered&#34;</span><span class="p">:</span><span class="kc">true</span><span class="p">,</span><span class="nt">&#34;expDate&#34;</span><span class="p">:</span><span class="s2">&#34;2099-01-01&#34;</span><span class="p">,</span><span class="nt">&#34;key&#34;</span><span class="p">:</span><span class="s2">&#34;&#34;</span><span class="p">}</span><span class="err">&#39;;</span>
</span></span><span class="line"><span class="cl">    <span class="err">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="err">location</span> <span class="err">/admin/service/registration/getStatus</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="err">default_type</span> <span class="err">application/json;</span>
</span></span><span class="line"><span class="cl">        <span class="err">return</span> <span class="err">200</span> <span class="err">&#39;{</span><span class="nt">&#34;deviceStatus&#34;</span><span class="p">:</span><span class="s2">&#34;0&#34;</span><span class="p">,</span><span class="nt">&#34;planType&#34;</span><span class="p">:</span><span class="s2">&#34;Lifetime&#34;</span><span class="p">,</span><span class="nt">&#34;subscriptions&#34;</span><span class="p">:{}}</span><span class="err">&#39;;</span>
</span></span><span class="line"><span class="cl">    <span class="err">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="err">location</span> <span class="err">/emby/Plugins/SecurityInfo</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="err">default_type</span> <span class="err">application/json;</span>
</span></span><span class="line"><span class="cl">        <span class="err">return</span> <span class="err">200</span> <span class="err">&#39;{</span><span class="nt">&#34;SupporterKey&#34;</span><span class="p">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="nt">&#34;IsMBSupporter&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">}</span><span class="err">&#39;;</span>
</span></span><span class="line"><span class="cl">    <span class="err">}</span>
</span></span><span class="line"><span class="cl"><span class="err">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以看到其中最为关键的是以下的几个点：</p>
<ol>
<li>设置好 servername 为验证网址的域名 mb3admin.com;</li>
<li>将以下的域名子路径都设置为返回对应的验证信息</li>
</ol>
<ul>
<li><code>/admin/service/registration/validateDevice</code></li>
<li><code>/admin/service/registration/validate</code></li>
<li><code>/admin/service/registration/getStatus</code></li>
<li><code>/emby/Plugins/SecurityInfo</code></li>
</ul>
<ol start="3">
<li>ssl_certificate 和 ssl_certificate_key 填写好对应的证书文件地址存放地址</li>
</ol>
<h3 id="hosts-文件修改">Hosts 文件修改</h3>
<p>linux 修改 host 文件地址：<code>/etc/hosts</code></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo <span class="nb">echo</span> <span class="s2">&#34;&lt;server_ip&gt;    &lt;domain_address&gt;&#34;</span> &gt;&gt; /etc/hosts</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>Windows 修改 host 文件地址：<code>C:\Windows\System32\drivers\etc\hosts</code></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">....
</span></span><span class="line"><span class="cl">&lt;server_ip&gt; &lt;domain_address&gt;</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>修改完立即刷新 dns 不需重启立即生效的方法,在 powershell 执行：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">ipconfig</span> <span class="p">/</span><span class="n">flushdns</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="test-服务测试">Test 服务测试</h2>
<p>完成上面的服务和 Host 修改后，可以登录对应的网站进行测试或者使用 curl 进行测试：</p>
<p>可以通过浏览器访问： <a href="https://mb3admin.com/admin/service/registration/validateDevice/" target="_blank" rel="noopener">https://mb3admin.com/admin/service/registration/validateDevice/</a>
 或者 <a href="https://mb3admin.com/admin/service/registration/validate/" target="_blank" rel="noopener">https://mb3admin.com/admin/service/registration/validate/</a>
 查看返回信息是否正确；</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231112095033.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231112095033.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231112095033.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>或者在 <strong>powershell</strong> 中执行以下命令查看返回信息是否正确，这里需要注意的是可能会与 WSL2 部署的 docker 混淆，但是该指令是否生效我们还是要在宿主机上的 powershell 查看。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">curl </span><span class="n">-ik</span> <span class="n">https</span><span class="err">:</span><span class="p">//</span><span class="n">mb3admin</span><span class="p">.</span><span class="n">com</span><span class="p">/</span><span class="n">admin</span><span class="p">/</span><span class="n">service</span><span class="p">/</span><span class="n">registration</span><span class="p">/</span><span class="n">validateDevice</span><span class="p">/</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231112095026.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231112095026.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231112095026.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><code>-k</code> 参数是为了忽略<strong>证书不受信任的 https 访问安全限制</strong>导致访问失败的问题。例如如下相关报错</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">&gt; Curl(60) issuer certificate is invalid </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果使用 curl 能够正常返回，但是网页的返回信息有误，或者无法打开网页，可能就要考虑如下的原因：</p>
<ul>
<li><strong>证书信任问题</strong>，可能要看是否正确配置和安装相关证书</li>
<li><strong>浏览器缓存问题</strong>，可以使用隐私(InPrivate)模式再次访问,或者清楚缓存后再次访问；</li>
<li><strong>代理的问题</strong>，具体的配置如下</li>
</ul>
<h3 id="clash-代理配置">Clash 代理配置</h3>
<p>若是由于设置了代理导致网站测试失败，这种情况下可以关掉代理再做测试，或者新增规则，配置验证网址不走代理。</p>
<p>配置规则的方法以 Clash 为例如下：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231111161114.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231111161114.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231111161114.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">parsers: # array
</span></span><span class="line"><span class="cl">    - url: &lt;你的订阅地址&gt;
</span></span><span class="line"><span class="cl">      yaml:
</span></span><span class="line"><span class="cl">        prepend-rules:
</span></span><span class="line"><span class="cl">            - DOMAIN-SUFFIX,&lt;直连的域名&gt;,DIRECT</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>添加 DOMAIN-SUFFIX 设置对应的域名为直链即可；</p>
<h3 id="activate-激活">Activate 激活</h3>
<p>访问 emby 服务页面，在 <code>emby premiere</code> 选单中随便选取密钥存储即可，这里会显示无效的密钥但是不要紧，可以切换主题看看是否已经激活成功。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231112100556.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231112100556.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231112100556.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>或者在控制台界面看是否已经有金标即可：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231112100635.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231112100635.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231112100635.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="ios-使用小火箭解锁-emby">IOS 使用小火箭解锁 emby</h2>
<p>详细图文请访问参考资料【5】，下面是简单的摘要：</p>
<p>第一步 default.conf（长按） -&gt; 编辑纯文本，将以下代码贴到底部：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="o">[</span>Script<span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">EmbyPremiere</span> <span class="o">=</span> <span class="nv">type</span><span class="o">=</span>http-response,script-path<span class="o">=</span>https://raw.githubusercontent.com/rartv/SurgeScript/main/EmbyPremiere/EmbyPremiere.js,pattern<span class="o">=</span>^https?:<span class="se">\/\/</span>mb3admin.com<span class="se">\/</span>admin<span class="se">\/</span>service<span class="se">\/</span>registration<span class="se">\/</span>validateDevice,max-size<span class="o">=</span>131072,requires-body<span class="o">=</span>true,timeout<span class="o">=</span>10,enable<span class="o">=</span><span class="nb">true</span>
</span></span><span class="line"><span class="cl"><span class="o">[</span>MITM<span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">hostname</span> <span class="o">=</span> mb3admin.com</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>第二步 default.conf（右侧的 i 按钮） -&gt; <code>https解密</code> （界面中应该会有 mb3admin.com 的域名信息）-&gt; 证书-&gt; 生成新的 CA 证书 -&gt; 安装证书 -&gt; 系统中信任证书</p>
<p>第三步打开 vpn，打开 emby，信任证书选择 ok，激活完成后可以关闭小火箭，后续失效的时候再打开一次即可。</p>
<h2 id="ref-参考资料">Ref 参考资料</h2>
<ol>
<li><a href="https://lengyue524.github.io/emby/2021/10/19/%E7%BE%A4%E6%99%96%E4%B8%8A%E5%88%A9%E7%94%A8%E7%8E%B0%E6%9C%89nginx%E6%90%AD%E5%BB%BAemby%E7%A0%B4%E8%A7%A3%E6%9C%8D%E5%8A%A1.html" target="_blank" rel="noopener">群晖上利用现有nginx搭建emby破解服务 (lengyue524)</a>
</li>
<li><a href="https://zhuangzhuang.io/2022/01/08/emby-carck.html" target="_blank" rel="noopener">Nas Emby 伪验证服务站搭建 - ZHUANGZHUANG</a>
</li>
<li><a href="https://hgl2.com/2023/unlock-emby/" target="_blank" rel="noopener">学习 Emby 解锁及优化 - Gallen&rsquo;s Blog (hgl2.com)</a>
</li>
<li><a href="https://velaciela.ms/emby-free-premier" target="_blank" rel="noopener">Emby全平台开心版、认证服务器设置方法 | Velaciela</a>
</li>
<li><a href="https://www.huluohu.com/posts/186/" target="_blank" rel="noopener">iOS利用小火箭解锁Emby | 胡萝虎的博客 (huluohu.com)</a>
</li>
</ol>
<h2 id="fi">Fi</h2>
]]></content:encoded>
    </item>
    <item>
      <title>使用Ipv6部署服务03 DDNS-go 动态域名解析</title>
      <link>https://aikenh.cn/posts/deploy_server_byipv6_03_ddnsgo/</link>
      <pubDate>Tue, 07 Nov 2023 13:40:13 +0000</pubDate>
      <guid>https://aikenh.cn/posts/deploy_server_byipv6_03_ddnsgo/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;本系列主要介绍通过公网的 ipv6 访问局域网设备并部署自己的服务供公网访问；本篇是其中的第三篇，以 DDNS-go 开源项目为例，部署动态域名解析服务，自动更新主机记录值。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/jeessy2/ddns-go&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;jeessy2/ddns-go: 简单好用的DDNS。自动更新域名解析到公网IP(支持阿里云、腾讯云、Dnspod、Cloudflare、Callback、华为云、百度云、Porkbun、GoDaddy、Google Domain) (github.com)&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;该工具使用起来非常简单，推荐需要动态域名解析的可以尝试使用该工具，简单介绍工具的使用如下：&lt;/p&gt;
&lt;h2 id=&#34;配置-ddns-go&#34;&gt;配置 DDNS-GO&lt;/h2&gt;
&lt;p&gt;前往 &lt;a href=&#34;https://github.com/jeessy2/ddns-go/releases/tag/v5.6.6&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;release&lt;/a&gt;
 页面下载对应系统的版本：&lt;/p&gt;
&lt;p&gt;
&lt;div class=&#34;post-img-view&#34;&gt;
  &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231108083156.png&#34;&gt;
    &lt;img alt=&#34;image.png&#34; loading=&#34;lazy&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231108083156.png&#34;class=&#34;responsive-image&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231108083156.png&#34; style=&#34;display: block; margin: 0 auto;&#34;
      alt=&#34;image.png&#34;  /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;script&gt;
  document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
      var images = document.querySelectorAll(&#34;.responsive-image&#34;);
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + &#34;px&#34;;
      });
  });
&lt;/script&gt;
&lt;/p&gt;
&lt;p&gt;解压后双击打开 ddns-go.exe 会自动弹出配置的界面：locahost:9876,选择需要解析域名的 DNS 服务商，选择创建密钥并填入对应的密钥。&lt;/p&gt;
&lt;p&gt;
&lt;div class=&#34;post-img-view&#34;&gt;
  &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231108083447.png&#34;&gt;
    &lt;img alt=&#34;image.png&#34; loading=&#34;lazy&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231108083447.png&#34;class=&#34;responsive-image&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231108083447.png&#34; style=&#34;display: block; margin: 0 auto;&#34;
      alt=&#34;image.png&#34;  /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;script&gt;
  document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
      var images = document.querySelectorAll(&#34;.responsive-image&#34;);
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + &#34;px&#34;;
      });
  });
&lt;/script&gt;
&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p>本系列主要介绍通过公网的 ipv6 访问局域网设备并部署自己的服务供公网访问；本篇是其中的第三篇，以 DDNS-go 开源项目为例，部署动态域名解析服务，自动更新主机记录值。</p>
</blockquote>
<p><a href="https://github.com/jeessy2/ddns-go" target="_blank" rel="noopener">jeessy2/ddns-go: 简单好用的DDNS。自动更新域名解析到公网IP(支持阿里云、腾讯云、Dnspod、Cloudflare、Callback、华为云、百度云、Porkbun、GoDaddy、Google Domain) (github.com)</a>
</p>
<p>该工具使用起来非常简单，推荐需要动态域名解析的可以尝试使用该工具，简单介绍工具的使用如下：</p>
<h2 id="配置-ddns-go">配置 DDNS-GO</h2>
<p>前往 <a href="https://github.com/jeessy2/ddns-go/releases/tag/v5.6.6" target="_blank" rel="noopener">release</a>
 页面下载对应系统的版本：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231108083156.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231108083156.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231108083156.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>解压后双击打开 ddns-go.exe 会自动弹出配置的界面：locahost:9876,选择需要解析域名的 DNS 服务商，选择创建密钥并填入对应的密钥。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231108083447.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231108083447.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231108083447.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>选择需要启用的 ipv4或者 ipv6解析服务,填写需要解析的域名（每个域名单独另起一行）</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231108083755.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231108083755.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231108083755.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>其他的保持默认即可，在这里完成了基础配置以后，<strong>记得点击保存</strong>，之后便可以<strong>安装对应的服务，使其后台自动更新</strong>，windows 使用管理员打开 powershell 或者 cmd，到对应目录下执行命令如下</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="p">.\</span><span class="n">ddns</span><span class="p">.</span><span class="py">go</span><span class="p">.</span><span class="py">exe</span> <span class="n">-s</span> <span class="n">install</span> <span class="o">-f</span> <span class="mf">10</span> <span class="n">-cacheTimes</span> <span class="mf">360</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><blockquote>
<p>通过合理的配置 <code>-f</code> 和 <code>-cacheTimes</code> 可以实现 IP 变化即时触发更新且不会被 DDNS 服务商限流, 例如 <code>-f 10 -cacheTimes 360</code> 效果为每 10 秒检查一次本地 IP 变化, 每小时去公网对比一下 IP 变化</p>
</blockquote>
<p>详细的配置可参考置顶的官网连接。</p>
<h2 id="fi">Fi</h2>
]]></content:encoded>
    </item>
    <item>
      <title>使用Ipv6部署服务02 Nginx和Https</title>
      <link>https://aikenh.cn/posts/deploy_server_byipv6_02_nginx/</link>
      <pubDate>Mon, 06 Nov 2023 20:49:16 +0000</pubDate>
      <guid>https://aikenh.cn/posts/deploy_server_byipv6_02_nginx/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;本系列主要介绍通过公网的 ipv6 访问局域网设备并部署自己的服务供公网访问；本篇是其中的第二篇，以腾讯云和 Nginx 为例，介绍如何将服务部署到 https://域名 。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;需要以下的事前准备：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;腾讯云/阿里云/Cloudflare 等随便一个地方购买一个自己的域名&lt;/li&gt;
&lt;li&gt;公网 ipv4/ipv6 地址&lt;/li&gt;
&lt;li&gt;本地部署一个服务以供测试&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;nginxdocker-安装&#34;&gt;Nginx(Docker) 安装&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;这里选择 Docker 来分离安装 Nginx 服务，Docker 部署的优势这里就不再赘述，这里建议使用 portainer 进行容器管理和运行状态查看。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;首先创建存放 Nginx 配置文件和证书文件的目录，后续挂载给 Nginx Contrainer 使用：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;div class=&#34;code-title&#34; onclick=&#34;toggleCode(this)&#34;&gt;
        
        &lt;span class=&#34;code-block-open&#34;&gt;&lt;ion-icon name=&#34;chevron-down-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/span&gt;
        &lt;span class=&#34;code-block-close&#34;&gt;&lt;ion-icon name=&#34;chevron-forward-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/ion-icon&gt;&lt;/span&gt;
        &lt;span&gt;shell&lt;/span&gt;
    &lt;/div&gt;
    &lt;div class=&#34;code-content&#34;&gt;
        
        &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir -p /home/username/docker-file/nginx/conf.d
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir -p /home/username/docker-file/nginx/cert&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === &#34;none&#34; || codeContent.style.display === &#34;&#34;) {
        codeContent.style.display = &#34;block&#34;; 
        codeContent.parentNode.classList.remove(&#34;code-has-hidden-child&#34;);
    } else {
        codeContent.style.display = &#34;none&#34;; 
        codeContent.parentNode.classList.add(&#34;code-has-hidden-child&#34;);
    }
}
&lt;/script&gt;&lt;blockquote&gt;
&lt;p&gt;配置文件存放到 &lt;code&gt;conf.d&lt;/code&gt; 中，&lt;strong&gt;各种 SSL 证书则存放到&lt;/strong&gt; &lt;code&gt;cert&lt;/code&gt; 文件夹中；&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p>本系列主要介绍通过公网的 ipv6 访问局域网设备并部署自己的服务供公网访问；本篇是其中的第二篇，以腾讯云和 Nginx 为例，介绍如何将服务部署到 https://域名 。</p>
</blockquote>
<p>需要以下的事前准备：</p>
<ul>
<li>腾讯云/阿里云/Cloudflare 等随便一个地方购买一个自己的域名</li>
<li>公网 ipv4/ipv6 地址</li>
<li>本地部署一个服务以供测试</li>
</ul>
<h2 id="nginxdocker-安装">Nginx(Docker) 安装</h2>
<blockquote>
<p>这里选择 Docker 来分离安装 Nginx 服务，Docker 部署的优势这里就不再赘述，这里建议使用 portainer 进行容器管理和运行状态查看。</p>
</blockquote>
<p>首先创建存放 Nginx 配置文件和证书文件的目录，后续挂载给 Nginx Contrainer 使用：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">mkdir -p /home/username/docker-file/nginx/conf.d
</span></span><span class="line"><span class="cl">mkdir -p /home/username/docker-file/nginx/cert</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><blockquote>
<p>配置文件存放到 <code>conf.d</code> 中，<strong>各种 SSL 证书则存放到</strong> <code>cert</code> 文件夹中；</p>
</blockquote>
<p>接着部署 Nginx，这次先不挂载目录，将 Nginx 中一些默认配置拷贝出来，以供后续使用和修改：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># run会自己执行镜像拉取，pull可以不执行</span>
</span></span><span class="line"><span class="cl"><span class="c1"># docker pull nginx</span>
</span></span><span class="line"><span class="cl">sudo docker run --name nginx -p 80:80 -d nginx </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>将配置文件复制出来：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo docker cp nginx:/etc/nginx/conf.d/default.conf /home/username/docker-file/nginx/conf.d/default.conf
</span></span><span class="line"><span class="cl">sudo docker cp nginx:/etc/nginx/nginx.conf /home/username/docker-file/nginx/conf.d/nginx.conf
</span></span><span class="line"><span class="cl">sudo docker cp nginx:/etc/nginx/mime.types /home/username/docker-file/nginx/conf.d/mime.types</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>基于原始的配置文件挂载后查看 nginx 是否正常运行：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo docker rm -f nginx
</span></span><span class="line"><span class="cl">sudo docker run --name nginx -p 80:80 -p 443:443 -v /home/username/docker-file/nginx/conf.d/nginx.conf:/etc/nginx/nginx.conf -v /home/username/docker-file/nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf -v /home/username/docker-file/nginx/conf.d/mime.types:/etc/nginx/mime.types -v /home/username/docker-file/nginx/cert:/etc/nginx/cert -d nginx</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>参考资料：<a href="https://www.cnblogs.com/Aamir-Ye/p/16823739.html" target="_blank" rel="noopener">使用docker部署nginx并配置https - 逊老头 - 博客园 (cnblogs.com)</a>
</p>
<h2 id="域名解析及申请免费-ssl-证书">域名解析及申请免费 SSL 证书</h2>
<blockquote>
<p>账号应该是有50个 SSL 证书限额，但是注意每个二级域名都需要单独申请 SSL 证书，例如 aiken.Com 和 videos.Aiken.Com 需要分别申请 SSL 证书。</p>
</blockquote>
<h3 id="域名解析">域名解析</h3>
<p>注册完域名后到域名控制台，选择特定的域名进行解析：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231107004308.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231107004308.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231107004308.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>主机记录可以设置 <code>www</code> 等二级域名，@既是基础域名（没有二级域名），IPV6的话设置记录类型为 AAAA，记录值这里填入公网 ipv6 地址（基于安全性考虑 Ipv6 地址大多会动态变化，包括 windows 会提供临时 ipv6 地址等等，后续会使用 DDNS-go 动态更新该地址）</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/1699289330400.png">
    <img alt="1699289330400.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/1699289330400.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/1699289330400.png" style="display: block; margin: 0 auto;"
      alt="1699289330400.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="ssl-证书申请">SSL 证书申请</h3>
<p>进入 SSL 证书管理界面 -&gt; 申请免费证书 -&gt; 提交证书申请 -&gt;</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231107005919.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231107005919.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231107005919.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>提交证书申请界面按照指引填写即可，域名部分记得二级域名也要单独申请即可。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231107010036.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231107010036.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231107010036.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>验证域名部分按照要求添加解析信息后点击验证域名即可，下载证书文件</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231107011115.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231107011115.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231107011115.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>耐心等待证书签发后，在我的证书界面下载证书，并将证书文件（解压后）放到挂载的 nginx 的 cert 目录中</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231107011305.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231107011305.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231107011305.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="nginx-配置部署服务">Nginx 配置部署服务</h2>
<blockquote>
<p>不同服务的 Nginx 配置在细节上会有一些差别，如果基础的设置不对，可以 Google 以下 Server+Nginx 查看是否有相关的文档说明，该部分简单介绍以下基本的一些写法。</p>
</blockquote>
<p>为了最大化的利用域名和单机服务，通常而言我们希望仅仅使用一个域名（包括其二级域名和二级目录）能够分别部署单机上分布于多个端口的多个服务，这里简单分别介绍如何为不同服务部署二级域名和二级目录。</p>
<p>需要注意的是，不同服务在部署的时候有不同的要求，<strong>有些服务涉及到一些 url 的跳转等问题，不支持二级目录的域名反代</strong>，会导致功能异常，具体需要参见相关文档，这种时候就推荐使用二级域名进行服务代理。</p>
<p>同时配置过程中<strong>需要注意反斜杠不要缺失，使用正确</strong>，不同的反斜杠最终会导致转向地址的不一致，参考：<a href="https://blog.csdn.net/clonetx/article/details/122305089" target="_blank" rel="noopener">nginx 反向代理斜杠问题_clonetx的博客-CSDN博客</a>
</p>
<h3 id="证书配置部分">证书配置部分</h3>
<p>证书配置部分主要按照签发处的指引，会给一个基础的模板，比如腾讯云：<a href="https://cloud.tencent.com/document/product/400/35244?from_cn_redirect=1" target="_blank" rel="noopener">SSL 证书 Nginx 服务器 SSL 证书安装部署-证书安装-文档中心-腾讯云 (tencent.com)</a>
</p>
<h3 id="二级地址反代">二级地址反代：</h3>
<p>在挂载的 conf.d 目录下的 default.conf 中新增 server 如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>conf</span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code class="language-conf" data-lang="conf">server {
     listen 443 ssl ;
     listen [::]:443 ssl;
     expires 12h;
     server_name metisy.cool;
     ssl_certificate /etc/nginx/cert/&lt;your domain&gt;.crt;
     ssl_certificate_key /etc/nginx/cert/&lt;your domain&gt;.key;
     ssl_session_timeout 5m;
     ssl_prefer_server_ciphers on;
    
    # FIXME: for safe reason disable this ---below---.
     location /dashboard/ {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Range $http_range;
        proxy_set_header If-Range $http_if_range;
        proxy_redirect off;
        proxy_pass &lt;url_local_server_address&gt;:&lt;port&gt;/;
        # the max size of file to upload
     }
}</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>其中</p>
<ul>
<li>&lt;url_local_server_address&gt;填写本地的局域网 ip 例如192.168.11.23</li>
<li>port 则填写该 ip 对应设备上提供服务的端口，例如1234</li>
<li>ssl_certificate 和 ssl_certificate_key 填写 ssl 证书对应的 crt 和 key 文件的路径</li>
</ul>
<h3 id="二级域名反代">二级域名反代</h3>
<p>在挂载的 conf.D 目录下的 default.Conf 中新增 server 如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>conf</span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code class="language-conf" data-lang="conf">server {
	listen 443 ssl ; 
	listen [::]:443 ssl;
	server_name {prefix_your domain}; 
	client_max_body_size 50000M;
	ssl_certificate /etc/nginx/cert/{prefix_your domain}.crt; 
	ssl_certificate_key /etc/nginx/cert/{prefix_your domain}.key; 
	ssl_session_timeout 5m;
	ssl_prefer_server_ciphers on;
	
	location / {
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto $scheme;
		proxy_set_header X-Forwarded-Protocol $scheme;
		proxy_set_header X-Forwarded-Host $http_host;
		proxy_buffering off;
		proxy_pass &lt;url_local_server_address&gt;:&lt;port&gt;/;
		#root /usr/share/nginx/html;
		#index  index.html index.htm;
	}
}</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>因为二级域名可以相当于一个新的域名，所以只需要把证书和 server_name 修改为新域名即可</p>
<h3 id="http-跳转https">Http 跳转Https</h3>
<p>在挂载的 conf.D 目录下的 default.Conf 中修改最上面的 server 为如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>conf</span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code class="language-conf" data-lang="conf">server {
    listen       80 default_server;
    listen  [::]:80 default_server;
    server_name  _;
    # rewrite ^(.*)$ https://metisy.cool:443/$1 permanent;
	return       301 https://$host$request_uri;
    #access_log  /var/log/nginx/host.access.log  main;

    # location / {
    #     root   /usr/share/nginx/html;
    #     index  index.html index.htm;
    # }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>使用 return(新) 或者 rewrite(旧) 命令，将针对该域名的 http 请求都重定向到 https 中。</p>
<h3 id="alist-的反向代理">Alist 的反向代理</h3>
<p>Alist 的反向代理参考如下文章：<a href="https://alist.nn.ci/zh/guide/install/reverse-proxy.html" target="_blank" rel="noopener">反向代理 | AList文档 (nn.ci)</a>
，如果不修改配置的话需要将其挂载在/根路径下，否则会导致出错，二级路径会导致无法正常运行，如果要挂载到子级目录/alist/下需要按照该文修改配置文件：<a href="https://alist.nn.ci/zh/faq/howto.html#%E5%A6%82%E4%BD%95%E5%AF%B9%E5%AD%90%E7%9B%AE%E5%BD%95%E8%BF%9B%E8%A1%8C%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86" target="_blank" rel="noopener">怎么做 | AList文档 (nn.ci)</a>
</p>
<p>此外，挂载完成后会发现由于 Nginx 缓存，会导致卡在登录界面无法进到主页面的问题，该问题可以通过在配置中取消缓存修复，修改 nginx 配置，添加该行：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231107133129.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231107133129.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231107133129.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="immich-的反向代理">Immich 的反向代理</h3>
<p>为了安全性和诸多其他考虑，不支持二级目录，建议使用二级域名挂载到根目录，具体的配置参考：</p>
<ul>
<li><a href="https://immich.app/docs/administration/reverse-proxy" target="_blank" rel="noopener">Reverse Proxy | Immich</a>
</li>
</ul>
<h3 id="xiaoya-alist-的反向代理">xiaoya Alist 的反向代理</h3>
<p>这里提一嘴，xiaoya 的 alist 的挂载目前也仅支持挂载到根路径，因此使用一个二级域名，个人暂时没找到如何挂载到子路径下，欢迎指正，万分感谢。</p>
<p>而如果是 xiaoya 的 emby 的反向代理，则需要手动重新映射一下 strm 资源库目录下的播放直链，将其改为挂载小雅的公网地址，可以使用以下脚本批量修改：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">find /home/user-dockerfile-dir/emby_res/xiaoya -name <span class="s2">&#34;*.strm&#34;</span> -exec sed <span class="se">\-</span>i <span class="s2">&#34;s#http://{locahost}:{port}#https://{domain}/#g; s# #%20#g;     s#|#%7C#g&#34;</span> <span class="o">{}</span> <span class="se">\;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这里的{localhost} {port} {domain}请自行修改成自己的对应地址，这样挂载出来的 emby 就可以在公网进行播放了。</p>
<h3 id="重启-nginx">重启 Nginx</h3>
<blockquote>
<p>完成上述所有对应的配置后，启动 Nginx，即可实现 https 访问对应的网站了。</p>
</blockquote>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># 可以删除当前contrainer重新部署</span>
</span></span><span class="line"><span class="cl">docker rm -f nginx
</span></span><span class="line"><span class="cl">sudo docker run --name nginx -p 80:80 -p 443:443 -v /home/username/docker-file/nginx/conf.d/nginx.conf:/etc/nginx/nginx.conf -v /home/username/docker-file/nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf -v /home/username/docker-file/nginx/conf.d/mime.types:/etc/nginx/mime.types -v /home/username/docker-file/nginx/cert:/etc/nginx/cert -d nginx</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>但是实际没必要那么麻烦，直接执行：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">docker restart nginx</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>即可，观察容器是否正常运行，如果运行失败查看 log 看是否哪里配置出错。</p>
<p>参考资料：</p>
<ul>
<li><a href="https://zhang.ge/5054.html" target="_blank" rel="noopener">Nginx通过二级目录（路径）映射不同的反向代理，规避IP+端口访问 | 张戈博客 (zhang.ge)</a>
</li>
<li><a href="https://www.quanxiaoha.com/docker/docker-nginx-install-ssl.html" target="_blank" rel="noopener">Docker Nginx 配置安装 SSL 证书（支持 Https 访问） - 犬小哈教程 (quanxiaoha.com)</a>
</li>
<li><a href="https://syq.pub/archives/27/?scroll=comment-4" target="_blank" rel="noopener">基于网盘挂载的emby服务端并实现直链播放 - syqman折腾笔记</a>
 基于小雅的方式的话无需参考该文，仅需将 address 文档替换成公网连接即可。</li>
<li><a href="https://note.youdao.com/ynoteshare/index.html?id=34790ec69ccaf38687664e96e0d8e46d&amp;type=note&amp;_time=1699094094800" target="_blank" rel="noopener">小雅Emby反代</a>
</li>
<li><a href="https://baijiahao.baidu.com/s?id=1630860688840962591" target="_blank" rel="noopener">nginx反向代理关闭缓存 (baidu.com)</a>
</li>
<li><a href="https://community.home-assistant.io/t/reverse-proxy-using-nginx/196954" target="_blank" rel="noopener">Reverse proxy using NGINX - Community Guides - Home Assistant Community (home-assistant.io)</a>
</li>
</ul>
<h2 id="troubleshooting-问题解决">TroubleShooting 问题解决</h2>



  
  

<blockquote class="alert-blockquote alert-bug">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Bug</span>
  </p>
  <p>访问域名 Nginx 显示 504 超时 error，直接使用局域网 ip 访问各个服务并无超时现象，各个服务运行正常，Nginx 使用默认页面也能正常访问。</p>

</blockquote>
<p>怀疑是由于 Docker、Windows、WSL2 更新之后网络的问题，导致 wsl2 可以访问各个局域网，但是 nginx 的 container 无法对各个局域网上的服务进行访问，因此采用 windows 宿主机直接安装 nginx 来避免此类网络问题，将 Nginx 添加到启动服务中，并将 WSL2 中的 nginx 配置迁移过来即可。</p>
<blockquote>
<p>WIN+R shell:starup 可打开启动文件夹，建立 nginx 的快捷方式后就可以在任务管理器中设置为启动项了。</p>
</blockquote>
<h2 id="fi">Fi</h2>
<p>本章就到这边，下一章节讲解由于 Ipv6 的动态特性，需要部署动态域名解析服务，这里以 ddns-go 为例，自动更新对应域名解析中的主机记录值。</p>
]]></content:encoded>
    </item>
    <item>
      <title>Win11 Docker服务的端口被异常占用</title>
      <link>https://aikenh.cn/posts/win11-docker%E6%9C%8D%E5%8A%A1%E7%9A%84%E7%AB%AF%E5%8F%A3%E8%A2%AB%E5%BC%82%E5%B8%B8%E5%8D%A0%E7%94%A8/</link>
      <pubDate>Sun, 05 Nov 2023 23:46:54 +0000</pubDate>
      <guid>https://aikenh.cn/posts/win11-docker%E6%9C%8D%E5%8A%A1%E7%9A%84%E7%AB%AF%E5%8F%A3%E8%A2%AB%E5%BC%82%E5%B8%B8%E5%8D%A0%E7%94%A8/</guid>
      <description>&lt;p&gt;Windows11基于 WSL2启动 docker 后报错如下（需要注意有时候使用启动命令会报错，但是 restart 命令 docker 可以运行，对应服务无法访问）&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Bind: An attempt was made to access a socket in a way forbidden by its access permissions.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;观察错误发现占用的信息为2345，从 windows 和 wsl 中分别查看端口是否被占用：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;div class=&#34;code-title&#34; onclick=&#34;toggleCode(this)&#34;&gt;
        
        &lt;span class=&#34;code-block-open&#34;&gt;&lt;ion-icon name=&#34;chevron-down-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/span&gt;
        &lt;span class=&#34;code-block-close&#34;&gt;&lt;ion-icon name=&#34;chevron-forward-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/ion-icon&gt;&lt;/span&gt;
        &lt;span&gt;powershell&lt;/span&gt;
    &lt;/div&gt;
    &lt;div class=&#34;code-content&#34;&gt;
        
        &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-powershell&#34; data-lang=&#34;powershell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;netstat&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;-aon&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;findstr&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;2345&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === &#34;none&#34; || codeContent.style.display === &#34;&#34;) {
        codeContent.style.display = &#34;block&#34;; 
        codeContent.parentNode.classList.remove(&#34;code-has-hidden-child&#34;);
    } else {
        codeContent.style.display = &#34;none&#34;; 
        codeContent.parentNode.classList.add(&#34;code-has-hidden-child&#34;);
    }
}
&lt;/script&gt;&lt;div class=&#34;code-block&#34;&gt;
    &lt;div class=&#34;code-title&#34; onclick=&#34;toggleCode(this)&#34;&gt;
        
        &lt;span class=&#34;code-block-open&#34;&gt;&lt;ion-icon name=&#34;chevron-down-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/span&gt;
        &lt;span class=&#34;code-block-close&#34;&gt;&lt;ion-icon name=&#34;chevron-forward-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/ion-icon&gt;&lt;/span&gt;
        &lt;span&gt;shell&lt;/span&gt;
    &lt;/div&gt;
    &lt;div class=&#34;code-content&#34;&gt;
        
        &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;netstat -tunlp &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep &lt;span class=&#34;m&#34;&gt;2345&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === &#34;none&#34; || codeContent.style.display === &#34;&#34;) {
        codeContent.style.display = &#34;block&#34;; 
        codeContent.parentNode.classList.remove(&#34;code-has-hidden-child&#34;);
    } else {
        codeContent.style.display = &#34;none&#34;; 
        codeContent.parentNode.classList.add(&#34;code-has-hidden-child&#34;);
    }
}
&lt;/script&gt;&lt;p&gt;均显示没有被占用，这可能是由于协议 tcp 使用的动态端口问题导致，可以使用管理员权限在 powershell 或者 cmd 中执行下列命令查看端口是否在动态范围中：&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Windows11基于 WSL2启动 docker 后报错如下（需要注意有时候使用启动命令会报错，但是 restart 命令 docker 可以运行，对应服务无法访问）</p>
<blockquote>
<p><strong>Bind: An attempt was made to access a socket in a way forbidden by its access permissions.</strong></p>
</blockquote>
<p>观察错误发现占用的信息为2345，从 windows 和 wsl 中分别查看端口是否被占用：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">netstat</span> <span class="n">-aon</span><span class="p">|</span><span class="n">findstr</span> <span class="s2">&#34;2345&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">netstat -tunlp <span class="p">|</span> grep <span class="m">2345</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>均显示没有被占用，这可能是由于协议 tcp 使用的动态端口问题导致，可以使用管理员权限在 powershell 或者 cmd 中执行下列命令查看端口是否在动态范围中：</p>
<blockquote>
<p>动态范围可能是由于 hyper-v 的原因修改过起始端口，所以可能会发现关闭 hyper-v 后没有占用的情况的现</p>
</blockquote>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">netsh</span> <span class="n">int</span> <span class="n">ipv4</span> <span class="n">show</span> <span class="n">dynamicport</span> <span class="n">tcp</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如在，修改动态范围，之后使用的时候避开这些端口即可。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">netsh</span> <span class="n">int</span> <span class="n">ipv4</span> <span class="nb">set </span><span class="n">dynamicport</span> <span class="n">tcp</span> <span class="n">start</span><span class="p">=</span><span class="mf">49152</span> <span class="n">num</span><span class="p">=</span><span class="mf">16384</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>重启电脑即可生效。</p>
]]></content:encoded>
    </item>
    <item>
      <title>使用Ipv6部署服务01 IPV6开启和设置</title>
      <link>https://aikenh.cn/posts/deploy_server_byipv6/</link>
      <pubDate>Sun, 05 Nov 2023 19:23:17 +0000</pubDate>
      <guid>https://aikenh.cn/posts/deploy_server_byipv6/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;本系列主要介绍通过公网的 ipv6 访问局域网设备并部署自己的服务供公网访问；本篇是其中的第一篇，以电信宽带为例，说明如何开启 ipv6 服务和外网访问放行。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;开启 IPV6 服务主要需要修改两个地方的配置：**光猫开启桥接模式和 IPV6 **、&lt;strong&gt;路由器修改为 pppoe 拨号模式以及防火墙设置&lt;/strong&gt;；这里以本人的电信光猫和小米路由器为例：&lt;/p&gt;
&lt;h2 id=&#34;背景介绍&#34;&gt;背景介绍&lt;/h2&gt;
&lt;p&gt;需要在外网访问部署于家庭内网的一些服务，考虑了以下的几个方案，决定使用 ipv6作为核心&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;/td&gt;
          &lt;td&gt;Zerotier&lt;/td&gt;
          &lt;td&gt;免费，需要注册账户，支持移动端，国内速度极慢，且不稳定&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;内网穿透&lt;/td&gt;
          &lt;td&gt;Tailscale（备用）&lt;/td&gt;
          &lt;td&gt;免费，需要注册账号，支持移动端，国内速度一版，稳定性相 Zetotier 较好，但仍不够稳定&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;内网穿透&lt;/td&gt;
          &lt;td&gt;frp&lt;/td&gt;
          &lt;td&gt;申请一个有公网的服务器，使用 frp 自己作为内网穿透的中转，贵，较为麻烦&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;公网 IP&lt;/td&gt;
          &lt;td&gt;Ipv4&lt;/td&gt;
          &lt;td&gt;难以申请，其他都好&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;公网 IP&lt;/td&gt;
          &lt;td&gt;Ipv6（主力）&lt;/td&gt;
          &lt;td&gt;获取简单，需要配置一下光猫使用，一劳永逸，快，稳定，多，有暴露公网的危险，需要设置防火墙&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;其他&lt;/td&gt;
          &lt;td&gt;Cloudflare Zerotrust&lt;/td&gt;
          &lt;td&gt;简单，免费，可以绑定域名，但是网站根本登不进去配置页面，速度不快&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;光猫设置&#34;&gt;光猫设置&lt;/h2&gt;
&lt;p&gt;查看光猫背面的管理员 url，进入光猫管理界面，登录&lt;strong&gt;超级管理员账户&lt;/strong&gt;（非普通账户，会跳转到更详细的管理页面，大部分同地区的超级管理员账户应该是一致的，不对可以询问下宽带师傅）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;管理地址通常为：192.168.1.1&lt;/li&gt;
&lt;li&gt;超级管理员账号：useradmin&lt;/li&gt;
&lt;li&gt;超级管理员密码：nE7jA%5&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;开始之前准备 PPPoe 拨号的帐号和密码，不知道的话等询问好了再开始操作。&lt;/p&gt;
&lt;p&gt;在天翼网关-&amp;gt;网络-&amp;gt;网络设置中进行如下的操作：（这里可以尝试改成 pppoe 并通过开发者模式查看密码，不知道密码不要轻易进行后续操作）&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;连接名称选择 &lt;code&gt;+++INTERENT_R_VID_41&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;连接模式从路由改为桥接&lt;/li&gt;
&lt;li&gt;IP 模式确认为 &lt;code&gt;IPv4&amp;amp;IPv6&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;点击保存/应用&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
&lt;div class=&#34;post-img-view&#34;&gt;
  &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105215512.png&#34;&gt;
    &lt;img alt=&#34;image.png&#34; loading=&#34;lazy&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105215512.png&#34;class=&#34;responsive-image&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105215512.png&#34; style=&#34;display: block; margin: 0 auto;&#34;
      alt=&#34;image.png&#34;  /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;script&gt;
  document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
      var images = document.querySelectorAll(&#34;.responsive-image&#34;);
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + &#34;px&#34;;
      });
  });
&lt;/script&gt;
&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p>本系列主要介绍通过公网的 ipv6 访问局域网设备并部署自己的服务供公网访问；本篇是其中的第一篇，以电信宽带为例，说明如何开启 ipv6 服务和外网访问放行。</p>
</blockquote>
<p>开启 IPV6 服务主要需要修改两个地方的配置：**光猫开启桥接模式和 IPV6 **、<strong>路由器修改为 pppoe 拨号模式以及防火墙设置</strong>；这里以本人的电信光猫和小米路由器为例：</p>
<h2 id="背景介绍">背景介绍</h2>
<p>需要在外网访问部署于家庭内网的一些服务，考虑了以下的几个方案，决定使用 ipv6作为核心</p>
<table>
  <thead>
      <tr>
          <th>类型</th>
          <th>方案</th>
          <th>简要说明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>内网穿透</td>
          <td>Zerotier</td>
          <td>免费，需要注册账户，支持移动端，国内速度极慢，且不稳定</td>
      </tr>
      <tr>
          <td>内网穿透</td>
          <td>Tailscale（备用）</td>
          <td>免费，需要注册账号，支持移动端，国内速度一版，稳定性相 Zetotier 较好，但仍不够稳定</td>
      </tr>
      <tr>
          <td>内网穿透</td>
          <td>frp</td>
          <td>申请一个有公网的服务器，使用 frp 自己作为内网穿透的中转，贵，较为麻烦</td>
      </tr>
      <tr>
          <td>公网 IP</td>
          <td>Ipv4</td>
          <td>难以申请，其他都好</td>
      </tr>
      <tr>
          <td>公网 IP</td>
          <td>Ipv6（主力）</td>
          <td>获取简单，需要配置一下光猫使用，一劳永逸，快，稳定，多，有暴露公网的危险，需要设置防火墙</td>
      </tr>
      <tr>
          <td>其他</td>
          <td>Cloudflare Zerotrust</td>
          <td>简单，免费，可以绑定域名，但是网站根本登不进去配置页面，速度不快</td>
      </tr>
  </tbody>
</table>
<h2 id="光猫设置">光猫设置</h2>
<p>查看光猫背面的管理员 url，进入光猫管理界面，登录<strong>超级管理员账户</strong>（非普通账户，会跳转到更详细的管理页面，大部分同地区的超级管理员账户应该是一致的，不对可以询问下宽带师傅）</p>
<ul>
<li>管理地址通常为：192.168.1.1</li>
<li>超级管理员账号：useradmin</li>
<li>超级管理员密码：nE7jA%5</li>
</ul>
<p>开始之前准备 PPPoe 拨号的帐号和密码，不知道的话等询问好了再开始操作。</p>
<p>在天翼网关-&gt;网络-&gt;网络设置中进行如下的操作：（这里可以尝试改成 pppoe 并通过开发者模式查看密码，不知道密码不要轻易进行后续操作）</p>
<ol>
<li>连接名称选择 <code>+++INTERENT_R_VID_41</code></li>
<li>连接模式从路由改为桥接</li>
<li>IP 模式确认为 <code>IPv4&amp;IPv6</code></li>
<li>点击保存/应用</li>
</ol>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105215512.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105215512.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105215512.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>在天翼网关-&gt;状态-&gt;网络侧信息中检查 IPv4 和 IPv6 是否都开启成功：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105215637.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105215637.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105215637.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>参考资料：<a href="https://cloud.tencent.com/developer/article/1894991" target="_blank" rel="noopener">个人宽带如何开启IPv6网络访问</a>
</p>
<h2 id="路由器设置">路由器设置</h2>
<p>进入小米路由器管理页面：192.168.31.1，选择上网设置并拉到上网设置部分</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105220425.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105220425.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105220425.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>将上网方式改成 PPPoE 并设置宽带账号和密码，在路由器进行拨号，其他保持默认即可。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105220642.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105220642.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105220642.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>拉到最下面 <strong>IPv6 网络设置</strong> ，将上网方式改为 Native ，自动配置 DNS，上网方式改为 Native，<strong>防火墙可以先关掉，测试一下连接后再打开，等完全配置好再最终关掉</strong>。</p>
<blockquote>
<p>由于大部分路由器都没有针对 ipv6 的防火墙规则设置，只有单纯的开或者关，所以我们再设置好 windows 防火墙和 https 后再打开。</p>
</blockquote>
<blockquote>
<p>这里 DNS 也可以选择手动设置为 ipv6 的 DNS，但我们只是为了公网访问本机的服务就不设置了</p>
</blockquote>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105222452.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105222452.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105222452.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>配置好之后应该会显示当前的 IPv6 网络信息：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105223926.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105223926.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105223926.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>可以用以下的几种方式验证是否真正开启成功：</p>
<ul>
<li><a href="https://test-ipv6.com/index.html.zh_CN" target="_blank" rel="noopener">IPv6 测试</a>
 网站</li>
<li><strong>Windows PowerShell</strong> 使用 <code>ipconfig/all</code> 查看 IPv6 信息，应该有以下的3条信息；
<ul>
<li>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105224822.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105224822.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231105224822.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</li>
</ul>
</li>
<li><strong>Linux/Raspberry Pi</strong> 使用 <code>hostname -I</code> 查看 ip 地址；</li>
<li>获取完 ipv6 地址后可以通过移动数据访问对应端口的服务来确认是否打开了公网访问。</li>
</ul>
<h2 id="防火墙设置">防火墙设置</h2>
<h3 id="windows-防火墙设置">Windows 防火墙设置</h3>
<p>参考官方文档对防火墙的设置：<a href="https://learn.microsoft.com/zh-cn/windows/security/operating-system-security/network-security/windows-firewall/turn-on-windows-firewall-and-configure-default-behavior" target="_blank" rel="noopener">启用具有高级安全性的Windows Defender防火墙并配置默认行为 - Windows Security | Microsoft Learn</a>
，并检查自己的防火墙设置：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231113084857.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231113084857.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231113084857.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>可以发现防火墙默认是阻止未设定的规则实现入站的，可以通过检查入站规则再关闭一些不安全的外网访问端口，</p>
<p>通过 <code>netstat -an | findstr &quot;LISTENING&quot;</code> 检查正在监听的窗口，并使用 telnet 检查是否开放端口开放（或者参见下列文章中提到的测试网址，最好是关闭了再去尝试）</p>
<p>禁止 ipv6 指定端口入站，如 135，3389，445，以及 446-65536 可以参考下列文章进行设置，其中 <code>2000::/3</code> 可以代表所有的公网 ipv6 地址；</p>
<ul>
<li>可以按照该文章，额外设置防火墙关闭3389端口 <a href="https://www.bilibili.com/read/cv25465237/" target="_blank" rel="noopener">「特别篇」在关闭光猫、路由器IPv6防火墙后可能遇到的安全问题 </a>
 ；</li>
</ul>
<h3 id="linux-防火墙设置">Linux 防火墙设置</h3>
<p>参考资料： <a href="https://www.digitalocean.com/community/tutorials/how-to-set-up-a-firewall-with-ufw-on-ubuntu-22-04" target="_blank" rel="noopener">How To Set Up a Firewall with UFW on Ubuntu 22.04 | DigitalOcean</a>
</p>
<p>使用 UFW 设置 linux 的防火墙，默认关闭外网访问，简单摘要以下需要执行的指令如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt-get install ufw
</span></span><span class="line"><span class="cl">sudo vim /etc/default/ufw
</span></span><span class="line"><span class="cl"><span class="c1"># 将其中的IPV6也设置为yes</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>开始配置 ufw，设置为默认禁止入站允许出站：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo ufw default deny incoming
</span></span><span class="line"><span class="cl">sudo ufw default allow outcoming</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>设置允许 SSH 连接和指定端口的出站，阻止 http 连接并启用 ufw：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo ufw allow ssh
</span></span><span class="line"><span class="cl">sudo ufw allow <span class="o">{</span>port<span class="o">}</span>
</span></span><span class="line"><span class="cl">sudo ufw deny http
</span></span><span class="line"><span class="cl">sudo ufw <span class="nb">enable</span>
</span></span><span class="line"><span class="cl"><span class="c1">#sudo ufw disable #为关闭服务</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>检查相关设置并删除错误的规则配置</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo ufw status verbose <span class="c1"># 查看设置，是否activate</span>
</span></span><span class="line"><span class="cl">sudo ufw status numbered <span class="c1"># 查看对应规则的idx，后续关闭该规则时候需要</span>
</span></span><span class="line"><span class="cl">sudo ufw delete <span class="o">{</span>idx<span class="o">}</span> <span class="c1"># 删除对应的规则</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>允许局域网网段访问</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo ufw allow from 192.168.1.0/24 to any port 【port】
</span></span><span class="line"><span class="cl"><span class="c1"># sudo ufw allow from 192.168.1.0/24 to any port 【port】proto tcp</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这里注意一下 kodi 可能需要8080，9090，9777这三个端口来支持遥控器的正常连接。</p>
<h3 id="https-设置">HTTPS 设置</h3>
<p>关注下后续设置服务部署的部分，会介绍通过 Nginx 和腾讯云部署 HTTPs.</p>
<h2 id="troubleshooting">Troubleshooting</h2>
<h3 id="路由器改桥接后访问光猫管理页面">路由器改桥接后访问光猫管理页面</h3>
<blockquote>
<p>&ldquo;光猫使用 Route 模式时，通过光猫的 DHCP 给下游设备地址（192.168.1.*），此时可以从下游终端访问到管理页面，而改为桥接模式时，则使用路由器的 DHCP 进行地址赋予(192.168.31.*), 无法访问光猫管理地址&rdquo;</p>
</blockquote>
<ol>
<li>网线连接光猫</li>
<li>将 ip 手动设置到光猫同一网段:192.168.1.Xx | 子网掩码 255.255.255.0</li>
<li>访问 192.168.1.1</li>
</ol>
<blockquote>
<p>使用完记得将 ip 修改回自动获取模式</p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>Obsidian使用 Spaced Repetition 制作闪念卡片</title>
      <link>https://aikenh.cn/posts/flashcard_template/</link>
      <pubDate>Sat, 28 Oct 2023 00:39:59 +0000</pubDate>
      <guid>https://aikenh.cn/posts/flashcard_template/</guid>
      <description>&lt;p&gt;该文作为基础的闪念卡片的使用说明，介绍几种闪念卡片定义的方式，便于后续查阅，参考：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://zhuanlan.zhihu.com/p/558326315&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Obsidian: Spaced Repetition插件使用指南 &lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.stephenmwangi.com/obsidian-spaced-repetition/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Index - Obsidian Spaced Repetition&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;基本规则&#34;&gt;基本规则&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;单个确定为 Flashcards 的笔记文件中可以存放多个闪念卡片。&lt;/li&gt;
&lt;li&gt;会根据记忆程度来设立需要复习的时间&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;卡片分组&#34;&gt;卡片分组&lt;/h2&gt;
&lt;p&gt;在 Tab 中使用 &lt;code&gt;/&lt;/code&gt; 可以引出卡片界面的层级，只需要在设置里设定最高层的分组，后续的分组用 &lt;code&gt;/&lt;/code&gt; 引出即可。&lt;/p&gt;
&lt;p&gt;
&lt;div class=&#34;post-img-view&#34;&gt;
  &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231027212958.png&#34;&gt;
    &lt;img alt=&#34;image.png&#34; loading=&#34;lazy&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231027212958.png&#34;class=&#34;responsive-image&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231027212958.png&#34; style=&#34;display: block; margin: 0 auto;&#34;
      alt=&#34;image.png&#34;  /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;script&gt;
  document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
      var images = document.querySelectorAll(&#34;.responsive-image&#34;);
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + &#34;px&#34;;
      });
  });
&lt;/script&gt;
&lt;/p&gt;
&lt;p&gt;使用以下的标签就能实现上述的分组结果：&lt;code&gt;#vocabulary/day00&lt;/code&gt;；需要注意到的是只有至少一个问答时才会显示在对应的表中。&lt;/p&gt;
&lt;h2 id=&#34;卡片制作&#34;&gt;卡片制作&lt;/h2&gt;
&lt;p&gt;在使用标签确定为 FlashCard 的页面可以使用如下的格式来定义一个一个的问答卡片，基础问答卡片的制作以如下的格式确认：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;div class=&#34;code-title&#34; onclick=&#34;toggleCode(this)&#34;&gt;
        
        &lt;span class=&#34;code-block-open&#34;&gt;&lt;ion-icon name=&#34;chevron-down-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/span&gt;
        &lt;span class=&#34;code-block-close&#34;&gt;&lt;ion-icon name=&#34;chevron-forward-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/ion-icon&gt;&lt;/span&gt;
        &lt;span&gt;txt&lt;/span&gt;
    &lt;/div&gt;
    &lt;div class=&#34;code-content&#34;&gt;
        
        &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Question :: Answer.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === &#34;none&#34; || codeContent.style.display === &#34;&#34;) {
        codeContent.style.display = &#34;block&#34;; 
        codeContent.parentNode.classList.remove(&#34;code-has-hidden-child&#34;);
    } else {
        codeContent.style.display = &#34;none&#34;; 
        codeContent.parentNode.classList.add(&#34;code-has-hidden-child&#34;);
    }
}
&lt;/script&gt;&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1&#34;&gt;
    &lt;script src=&#34;https://cdn.jsdmirror.com/npm/jquery@3.3.1/dist/jquery.min.js&#34;&gt;&lt;/script&gt;
    &lt;link rel=&#34;stylesheet&#34; href=&#34;https://cdn.jsdmirror.com/npm/nanogallery2@3.0.5/dist/css/nanogallery2.min.css&#34;&gt;
    &lt;script src=&#34;https://cdn.jsdmirror.com/npm/nanogallery2@3.0.5/dist/jquery.nanogallery2.min.js&#34;&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;div data-nanogallery2=&#39;{
	 &#34;thumbnailDisplayTransition&#34;:          &#34;none&#34;,
     &#34;thumbnailDisplayTransitionDuration&#34;:  500,
     &#34;thumbnailDisplayInterval&#34;:            30,
     &#34;galleryDisplayTransition&#34;:            &#34;none&#34;,
     &#34;galleryDisplayTransitionDuration&#34;:    500,
     &#34;galleryDisplayMode&#34;: &#34;rows&#34;,
     &#34;thumbnailDisplayOutsideScreen&#34;: &#34;false&#34;,
     &#34;eventsDebounceDelay&#34;: 10,
     &#34;thumbnailL1BorderHorizontal&#34;: 0,
     &#34;thumbnailL1BorderVertical&#34;: 0,
     &#34;thumbnailLabel&#34;: {
        &#34;titleFontSize&#34;: &#34;0.6em&#34;
     },
     &#34;thumbnailHoverEffect2&#34;: &#34;image_scale_1.00_1.10|label_backgroundColor_rgba(0,0,0,0)_rgba(255,255,255,0)&#34;,
     &#34;galleryTheme&#34;: {
        &#34;thumbnail&#34;: {
            &#34;borderRadius&#34;: &#34;8px&#34;
        }
     },
     &#34;thumbnailToolbarImage&#34;: {
        &#34;topLeft&#34;: &#34;&#34;,
        &#34;topRight&#34;: &#34;&#34;,
        &#34;bottomLeft&#34;: &#34;&#34;,
        &#34;bottomRight&#34;: &#34;&#34;
     },
     &#34;viewerToolbar&#34;:   {
        &#34;display&#34;: true,
        &#34;standard&#34;: &#34;label&#34;
     },
     &#34;viewerTools&#34;:     {
        &#34;topLeft&#34;:    &#34;pageCounter, playPauseButton&#34;,
        &#34;topRight&#34;:   &#34;downloadButton, rotateLeft, zoomButton, fullscreenButton, closeButton&#34;
     },
     &#34;viewerGalleryTWidth&#34;: 40,
     &#34;viewerGalleryTHeight&#34;: 40
}&#39;&gt;
     
&lt;a href=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231027232414.png&#34; data-ngThumb=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231027232414.png&#34;&gt;&lt;/a&gt;

&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
&lt;h3 id=&#34;单行翻转卡片&#34;&gt;单行翻转卡片&lt;/h3&gt;
&lt;p&gt;进行问答的翻转，会将一张卡变为两张，正反各问一遍，互为答案与问题；&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>该文作为基础的闪念卡片的使用说明，介绍几种闪念卡片定义的方式，便于后续查阅，参考：</p>
<ul>
<li><a href="https://zhuanlan.zhihu.com/p/558326315" target="_blank" rel="noopener">Obsidian: Spaced Repetition插件使用指南 </a>
</li>
<li><a href="https://www.stephenmwangi.com/obsidian-spaced-repetition/" target="_blank" rel="noopener">Index - Obsidian Spaced Repetition</a>
</li>
</ul>
<h2 id="基本规则">基本规则</h2>
<ul>
<li>单个确定为 Flashcards 的笔记文件中可以存放多个闪念卡片。</li>
<li>会根据记忆程度来设立需要复习的时间</li>
</ul>
<h2 id="卡片分组">卡片分组</h2>
<p>在 Tab 中使用 <code>/</code> 可以引出卡片界面的层级，只需要在设置里设定最高层的分组，后续的分组用 <code>/</code> 引出即可。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231027212958.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231027212958.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231027212958.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>使用以下的标签就能实现上述的分组结果：<code>#vocabulary/day00</code>；需要注意到的是只有至少一个问答时才会显示在对应的表中。</p>
<h2 id="卡片制作">卡片制作</h2>
<p>在使用标签确定为 FlashCard 的页面可以使用如下的格式来定义一个一个的问答卡片，基础问答卡片的制作以如下的格式确认：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">Question :: Answer.</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><!DOCTYPE html>
<html lang="en">
<head>
    <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
    <script src="https://cdn.jsdmirror.com/npm/jquery@3.3.1/dist/jquery.min.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdmirror.com/npm/nanogallery2@3.0.5/dist/css/nanogallery2.min.css">
    <script src="https://cdn.jsdmirror.com/npm/nanogallery2@3.0.5/dist/jquery.nanogallery2.min.js"></script>
</head>
<body>

<div data-nanogallery2='{
	 "thumbnailDisplayTransition":          "none",
     "thumbnailDisplayTransitionDuration":  500,
     "thumbnailDisplayInterval":            30,
     "galleryDisplayTransition":            "none",
     "galleryDisplayTransitionDuration":    500,
     "galleryDisplayMode": "rows",
     "thumbnailDisplayOutsideScreen": "false",
     "eventsDebounceDelay": 10,
     "thumbnailL1BorderHorizontal": 0,
     "thumbnailL1BorderVertical": 0,
     "thumbnailLabel": {
        "titleFontSize": "0.6em"
     },
     "thumbnailHoverEffect2": "image_scale_1.00_1.10|label_backgroundColor_rgba(0,0,0,0)_rgba(255,255,255,0)",
     "galleryTheme": {
        "thumbnail": {
            "borderRadius": "8px"
        }
     },
     "thumbnailToolbarImage": {
        "topLeft": "",
        "topRight": "",
        "bottomLeft": "",
        "bottomRight": ""
     },
     "viewerToolbar":   {
        "display": true,
        "standard": "label"
     },
     "viewerTools":     {
        "topLeft":    "pageCounter, playPauseButton",
        "topRight":   "downloadButton, rotateLeft, zoomButton, fullscreenButton, closeButton"
     },
     "viewerGalleryTWidth": 40,
     "viewerGalleryTHeight": 40
}'>
     
<a href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231027232414.png" data-ngThumb="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231027232414.png"></a>

</div>
</body>
</html>
<h3 id="单行翻转卡片">单行翻转卡片</h3>
<p>进行问答的翻转，会将一张卡变为两张，正反各问一遍，互为答案与问题；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">Question ::: Answer</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>效果与单卡相似，只是多了一张卡，这里不再展示。</p>
<h3 id="多行问答">多行问答</h3>
<ul>
<li><code>?</code> 分割问题和回答，此时的问题和回答都可以使用多行文本，便于编写复杂文本的问题。</li>
<li>类似的文本翻转可以使用 <code>??</code> 实现多行文本翻转</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">Multi Line Question1
</span></span><span class="line"><span class="cl">Question2
</span></span><span class="line"><span class="cl">??
</span></span><span class="line"><span class="cl">Answer1
</span></span><span class="line"><span class="cl">Answer2</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="完形填空">完形填空</h3>
<p>使用 == 连等号==框起来的文本==将会被自动识别为完形填空, 例如以下情况：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">Using ==Obsidian== plugin to achieve ==flashcard== function</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>会分别识别成两个卡片，将 Obsidian 和 Flashcard 作为完形填空的问题，效果如下所示：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231028003022.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231028003022.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231028003022.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<img src=" https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231028003101.png" style="zoom:50%;">
<h2 id="fi">FI</h2>
]]></content:encoded>
    </item>
    <item>
      <title>VsCode&#39;s RegExp Catch 正则捕获</title>
      <link>https://aikenh.cn/posts/vsocde_regexp/</link>
      <pubDate>Thu, 19 Oct 2023 16:53:03 +0000</pubDate>
      <guid>https://aikenh.cn/posts/vsocde_regexp/</guid>
      <description>using RegExp to search and replace</description>
      <content:encoded><![CDATA[<p>本篇简单介绍一些 VsCode 进行文本替换和查找的一些特殊的正则，该文会随着自己的使用来逐步记录，目前主要内容如下：</p>
<ul>
<li>捕获组合及其替换模式</li>
</ul>
<p>这里不会介绍正则表达式的语法，对其基本语法感兴趣可以查看如下链接 <a href="https://learn.microsoft.com/zh-cn/visualstudio/ide/using-regular-expressions-in-visual-studio?view=vs-2022" target="_blank" rel="noopener">VsCode使用正则表达式</a>
，以及我之前写过的<a href="https://aikenh.cn/cn/Linux%E4%B8%89%E5%89%91%E5%AE%A2%E4%B9%8B%E6%AD%A3%E5%88%99/" target="_blank" rel="noopener">基础的正则表达式</a>
 一文，下面进入正题；</p>
<h2 id="intro-正则搜索">Intro 正则搜索</h2>
<p>正则表达式主要思路为<strong>模式匹配</strong>，通过符号表达来指定一种模式，识别所有符合该模式的字符组合，而非某些<strong>特定的文字</strong>，因此可以简化我们的搜索和替换过程，下面以一个例子说明。</p>
<p>例如有一个文件配置如下，而我们希望找到其中所有 <code>user_config</code> ，查看每个 user 的设置是否正确，由于 username 的长度和内容都不是一样的，所以这里需要使用正则来进行搜索：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">zxc1_config=123
</span></span><span class="line"><span class="cl">some content we dont need
</span></span><span class="line"><span class="cl">asd2_config=234
</span></span><span class="line"><span class="cl">and some other infomation or comment
</span></span><span class="line"><span class="cl">qwer3_config=345</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>对应该场景的正则表达则为 <code>+*_config=</code> 或者 <code>[a-z, 0-9]*_config=</code> 等写法均可，效果如下：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231019173213.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231019173213.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231019173213.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>可以看到我们需要的内容都被高亮了，这也就方便了我们进行一些复杂的文字处理，而搜索，也就是正则最基本也是最正统的用法，这里不再多说。</p>
<h2 id="catch-捕获组合与正则替换">Catch 捕获组合与正则替换</h2>
<p>这里主要要介绍的是在替换中使用正则。同时实现样式的保留和替代，可以看以下的例子：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">aiken_config_file_path_1=res/user/aikenhong/code_config_2m.txt
</span></span><span class="line"><span class="cl">aiken_config_file_path_2=res/user/aikenhong/code_config_4m.txt
</span></span><span class="line"><span class="cl">aiken_config_file_path_33=res/user/kiean/config_special.txt
</span></span><span class="line"><span class="cl">...
</span></span><span class="line"><span class="cl">kiean_config_file_path_1=res/user/aikenhong/code_config_2m.txt
</span></span><span class="line"><span class="cl">some other content and comment here.
</span></span><span class="line"><span class="cl">...</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以看到该文件定义了不同用户的不同编号的配置文件的地址，假如由于测试的原因，需要将 aiken_的所有配置文件都暂时以一个新的 <code>res/user/aikenhong/tmp.txt</code> 替代，分析可知此时为了不影响 kiean 等其他人的配置受到影响</p>
<ul>
<li>我们需要识别出 <code>aiken_config_file</code> 中的 aiken</li>
<li>需要保留 <code>aiken_config_file_{n}</code> 中的序号 n</li>
</ul>
<p>这里使用普通正则会遇到的问题就是：<strong>如何保留匹配到的序号这个样式</strong>，并在替换的时候调用它？在 VsCode 中，可以在<strong>搜索使用 <code>()</code> 保留样式，并在替换时使用 <code>$n</code> 来调用指定 idx 的样式，n 从1开始</strong>。</p>
<p>所以上述问题使用的搜索和替换表达式分别为:</p>
<ul>
<li><code>aiken_config_file_path_([0-9]+)=.*txt</code></li>
<li>``aiken_config_file_path_$1=res/user/aikenhong/tmp.txt`</li>
</ul>
<p>替换前搜索的效果如下：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231019175657.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231019175657.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231019175657.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>替换后的效果如下：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231019175748.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231019175748.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231019175748.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>其中+表示匹配1次或以上，保证 idx 为多位的情况不被遗漏，[0-9] 匹配数字，当然也可以加入对字母的匹配，()获取并保留当前匹配到的样式，并在替换过程中使用$1进行调用。</p>
<p><strong>总结</strong>很简单如下，实际难点仅在熟悉正则表达式的使用</p>
<ul>
<li>搜索使用 <code>()</code> 保留样式</li>
<li>并在替换时使用 <code>$n</code> 来调用指定 idx 的样式</li>
<li>n 从1开始</li>
</ul>
<h2 id="fi">Fi</h2>
]]></content:encoded>
    </item>
    <item>
      <title>HomeAssistant01 入门基础篇</title>
      <link>https://aikenh.cn/posts/homeassistant_init/</link>
      <pubDate>Sat, 12 Aug 2023 17:24:50 +0000</pubDate>
      <guid>https://aikenh.cn/posts/homeassistant_init/</guid>
      <description>基于Docker安装和配置HA，并提供一些初始的配置选项。</description>
      <content:encoded><![CDATA[<blockquote>
<p>接下来本文安装的是 Container 版本的 HA，并非 Supervised 的版本，所以其中是不包含 Add-on 的，如果需要特定的 Add-on 的版本请注意。</p>
</blockquote>
<p>基于本篇流程安装 HA 的前置条件是系统上已经安装好了可用的 Docker，该文会介绍 HA 和 HACS 的安装以及一些基础的配置。</p>
<h2 id="ha--hacs-安装">HA &amp; HACS 安装</h2>
<blockquote>
<p>本文安装于 Raspberry pi 4B，与其他操作环境可能会存在一些差异，要注意甄别。</p>
</blockquote>
<h3 id="ha">HA</h3>
<p>安装过程主要参考 <a href="https://www.home-assistant.io/installation/raspberrypi" target="_blank" rel="noopener">Raspberry Pi - Home Assistant </a>
 中 Install Home Assistant Container 的章节，如果为其他的 OS 也可以在官网找到类似的指引，不过 docker 版本的差异应该不会特别的大，个人的 Docker Compose File 也已经上传到 <a href="https://github.com/AikenH/aikenh-DockerComposeYML/blob/master/HomeAssistant/docker-compose.yml" target="_blank" rel="noopener">GITHUB</a>
 可自行取用。</p>
<p>修改完 <code>-v</code> 的挂载目录以后（将数据保存在本地的目录）和 <code>-e</code> 的时区后，即可执行拉取和安装 docker，这里-v 挂载的本地目录要记得，后面有用。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker compose up -d </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>安装完后基于 Host 模式的 HA 会运行在 http://localhost:8123 中，localhost 也可以用 ip 替代。安装完后随着<a href="https://www.home-assistant.io/getting-started/onboarding/" target="_blank" rel="noopener">指引</a>
完成一些基础的设置，设置好默认的账号密码即可重启 docker 进入 HA 的界面；</p>
<p>到这里已经可以做一些基础的使用了，但是为了支持更多智能家具产品，往往需要安装第三方用户商店 HACS ，从中去下载对于其他智能家具产品的支持。</p>
<h3 id="hacs">HACS</h3>
<blockquote>
<p>Home Assistant Community Store 第三方用户商店，便于下载各种各样的集成实现对于各个不同智能家具品牌和产品的支持。</p>
</blockquote>
<p>各种不同版本的安装方式可以参考<a href="https://hacs.xyz/docs/setup/download" target="_blank" rel="noopener">官方网页</a>
，以下只介绍基于 Container 的安装方式，官方提供了安装脚本，因此现在下载已经相对简单，具体如下：</p>
<ul>
<li>进入挂载的本地目录，执行下面命令，即包含了下载和执行。</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">wget -O - https://get.hacs.xyz <span class="p">|</span> bash -</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><blockquote>
<p>如果下不下来也可以直接打开网页复制进.Sh 脚本中；也可以去我的仓库中拉下来</p>
</blockquote>
<p>安装完重启 HA，在集成页面添加集成，搜索 HACS，搜索到直接进行安装，跟随配置进行安装，并打开 GITHUB 进行登录和授权即可。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812180304.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812180304.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812180304.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812180357.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812180357.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812180357.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>查看是否出现了 HACS 的选项，如果安装完后面出现了如下的界面即为安装完成。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812175508.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812175508.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812175508.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>由于后续的一些社区插件都是需要从 Github 拉取，因此需要为 HACS 设置代理，目前版本的代理设置在如下位置：<code>&lt;挂载的本地目录/即HA的config文件夹&gt;/custom_compomemts/hacs/base.py</code>。</p>
<p>使用编辑器打开该文件进行修改，搜索到 <code>session.get(url = url</code> 的字段，添加自己的 proxy 设置如下。重启即可，可以在设置搜索到重启服务进行重启。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812180027.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812180027.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812180027.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>该方法参考于：<a href="https://bbs.hassbian.com/thread-15358-1-1.html" target="_blank" rel="noopener">HACS更新后怎么添加代理从而顺畅下载 - 『HomeAssistant』综合讨论区 - 『瀚思彼岸』» 智能家居技术论坛 - Powered by Discuz! (hassbian.com)</a>
</p>
<blockquote>
<p>如果无法直接安装，也可以直接上 github 界面下载压缩包，解压到 custom_components 文件夹中。</p>
</blockquote>
<h2 id="一些简单的基础配置和说明">一些简单的基础配置和说明</h2>
<blockquote>
<p>完成上述安装后，就可以开始搭建自己的 HA 系统了，该部分简单对逻辑和一些集成的使用进行说明介绍；</p>
</blockquote>
<h3 id="简单说明">简单说明</h3>
<p>基于个人的粗浅入门尝试，HA 的配置可以简单理解为实体 entity 和 UI 模板 lovelace 的组合，两者结合来构成我们的控制中心和可视化界面。</p>
<ul>
<li>实体既是智能家居中的各种物件组成，如：灯泡，开关，电视，温度计等，其主要提供：数据源（用于显示和统计），以及控制单元和权限（开关，温度设置等）</li>
<li>Lovelace 是针对 HA 集成的 UI 模块，其为一种或多种类型的实体提供可视化方案，基于 UI 模块结合读取的实体信息来设计我们的控制台。</li>
</ul>
<blockquote>
<p>Lovelace is <strong>the user interface that has been packaged with Home Assistant</strong> and has been the standard for several versions now.</p>
</blockquote>
<p>因此，安装 HA 中自带的一些集成和 HACS 提供的额外集成提供的是：对各种智能家具的<strong>数据</strong>和<strong>控制权限</strong>的获取能力。</p>
<p>一开始安装完 HA 可以发现其已经默认可以获取一些实体了，这些可以都勾上，然后可以去上述安装 hacs 集成的地方勾选一些有用的系统集成安装，这些实体和默认的一些 UI 的界面可以自行尝试搭配。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812182406.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812182406.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812182406.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812182553.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812182553.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812182553.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="添加系统信息监控">添加系统信息监控</h3>
<p>在 <code>&lt;挂载的本地目录/即HA的config文件夹&gt;/configuration.yml</code> 中添加系统监管信息如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">sensor</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="nt">platform</span><span class="p">:</span><span class="w"> </span><span class="l">systemmonitor</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">resources</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">memory_use_percent</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">disk_use_percent</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">processor_use</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">last_boot</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">processor_temperature</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">memory_free</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以添加的选项可以在<a href="https://www.home-assistant.io/integrations/systemmonitor/" target="_blank" rel="noopener">官方页面查看</a>
 ，配置完成后重启 HA 即可在实体中看到对应的选项。</p>
<h3 id="小米系列设备">小米系列设备</h3>
<p>通过在 HACS 中安装 Xiaomi Miot Auto 集成，即可添加诸多小米的设备，空调伴侣也可简单的实现集成。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812184812.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812184812.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812184812.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="onvir-监视器设备添加">Onvir 监视器设备添加</h3>
<p>HA 集成中添加 onvir 集成，添加对应的 IP 和用户名密码即可添加对应摄像头。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812185244.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812185244.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230812185244.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="小米温湿度计2代">小米温湿度计2代</h3>
<p>参考： <a href="https://blog.csdn.net/weixin_43529394/article/details/130600751" target="_blank" rel="noopener">【HA】HomeAssistant 添加 小米温湿度计2代_小米温湿度计接入ha_叼辣条闯天涯的博客-CSDN博客</a>
</p>
<p>HACS 安装 passive ble monitor intgration 集成</p>
<ul>
<li>
<p>通过此 <a href="https://atc1441.github.io/TelinkFlasher.html" target="_blank" rel="noopener">Telink Flasher for Mi Thermostat</a>
 点击 Connect，</p>
<ul>
<li>选择设备 LYWSD03MMC 进行配对连接</li>
<li>显示了 Connected 后，点击 Do Activation</li>
<li>获取32位密钥 Mi Bind Key</li>
</ul>
</li>
<li>
<p>获取 MAC 地址</p>
<ul>
<li>终端中使用蓝牙搜索对应设备</li>
<li>使用以下的命令扫描蓝牙设备，由于是被动接受信号，所以可能需要等待一段时间，等待 LYWSD03MMC 设备出现</li>
</ul>
</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">bluetoothctl
</span></span><span class="line"><span class="cl"><span class="c1"># 进入蓝牙连接命令行后</span>
</span></span><span class="line"><span class="cl">scan on
</span></span><span class="line"><span class="cl"><span class="c1"># 等待LYWSD03MMC设备出现</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>添加集成：Passive BLE monitor，选择树莓派的蓝牙进入下一步，选择 <code>Add device</code>，在新的窗口中配置设备；仅需添加 <strong>MAC 地址</strong>和<strong>加密密钥选项</strong>，选择提交后会返回到上一个界面而不是没反应。</p>
<p>将设备选项放在 <code>--Devices--</code> 直接提交即可，由于设备广播需要一定的时间，因此需要耐心等待一定时间即可。</p>
<h2 id="troubleshoot-问题解决">TroubleShoot 问题解决</h2>
<h3 id="clear-banned-ips-解除-ip-封禁">Clear Banned Ips 解除 IP 封禁</h3>
<p>使用 Nginx 部署 HA 服务后，由于密码输入错误和密码尝试次数限制等原因，可能会导致 IP 被 HA 封禁，这种情况下可以通过手动编辑配置文件中的 <code>ip_bans.yaml</code> 文件（和 configuration.Yaml 在同一个目录下），删除自己的 IP 从而实现解封。</p>
<p>参考资料：<a href="https://community.home-assistant.io/t/clear-banned-lan-ips/124440" target="_blank" rel="noopener">Clear Banned LAN IPs - Installation / Home Assistant OS - Home Assistant Community (home-assistant.io)</a>
</p>
<h2 id="fi">FI</h2>
<p>分享一下个人的成品：</p>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
    <script src="https://cdn.jsdmirror.com/npm/jquery@3.3.1/dist/jquery.min.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdmirror.com/npm/nanogallery2@3.0.5/dist/css/nanogallery2.min.css">
    <script src="https://cdn.jsdmirror.com/npm/nanogallery2@3.0.5/dist/jquery.nanogallery2.min.js"></script>
</head>
<body>

<div data-nanogallery2='{
	 "thumbnailDisplayTransition":          "none",
     "thumbnailDisplayTransitionDuration":  500,
     "thumbnailDisplayInterval":            30,
     "galleryDisplayTransition":            "none",
     "galleryDisplayTransitionDuration":    500,
     "galleryDisplayMode": "rows",
     "thumbnailDisplayOutsideScreen": "false",
     "eventsDebounceDelay": 10,
     "thumbnailL1BorderHorizontal": 0,
     "thumbnailL1BorderVertical": 0,
     "thumbnailLabel": {
        "titleFontSize": "0.6em"
     },
     "thumbnailHoverEffect2": "image_scale_1.00_1.10|label_backgroundColor_rgba(0,0,0,0)_rgba(255,255,255,0)",
     "galleryTheme": {
        "thumbnail": {
            "borderRadius": "8px"
        }
     },
     "thumbnailToolbarImage": {
        "topLeft": "",
        "topRight": "",
        "bottomLeft": "",
        "bottomRight": ""
     },
     "viewerToolbar":   {
        "display": true,
        "standard": "label"
     },
     "viewerTools":     {
        "topLeft":    "pageCounter, playPauseButton",
        "topRight":   "downloadButton, rotateLeft, zoomButton, fullscreenButton, closeButton"
     },
     "viewerGalleryTWidth": 40,
     "viewerGalleryTHeight": 40
}'>
     
<a href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/32835f5c84cc6778289bd656c0910c5.jpg" data-ngThumb="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/32835f5c84cc6778289bd656c0910c5.jpg"></a>
<a href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/85dbfd146eb1041939a643b11775835.jpg" data-ngThumb="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/85dbfd146eb1041939a643b11775835.jpg"></a>

</div>
</body>
</html>
]]></content:encoded>
    </item>
    <item>
      <title>linux下载命令之Wget和Curl</title>
      <link>https://aikenh.cn/posts/linuxcli_download/</link>
      <pubDate>Fri, 07 Jul 2023 22:10:52 +0000</pubDate>
      <guid>https://aikenh.cn/posts/linuxcli_download/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;想要通过命令行直接下载文件，通常想到的就是下面的两个工具：wget 和 curl，下面简单介绍一下两者的使用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;wget&#34;&gt;Wget&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;wget&lt;/code&gt; 全称为 &lt;code&gt;web get&lt;/code&gt; ，其基本用法为：&lt;code&gt;wget [-para] url &lt;/code&gt; ，常用的参数有以下几种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;-O 指定下载文件的保存名称&lt;/li&gt;
&lt;li&gt;-b 为后台下载模式&lt;/li&gt;
&lt;li&gt;-P 下载到指定目录&lt;/li&gt;
&lt;li&gt;-c 支持断电续传&lt;/li&gt;
&lt;li&gt;-p 下载页面内的所有资源、包括图片视频等&lt;/li&gt;
&lt;li&gt;-r 递归下载&lt;/li&gt;
&lt;li&gt;-t 最大尝试次数&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;div class=&#34;code-title&#34; onclick=&#34;toggleCode(this)&#34;&gt;
        
        &lt;span class=&#34;code-block-open&#34;&gt;&lt;ion-icon name=&#34;chevron-down-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/span&gt;
        &lt;span class=&#34;code-block-close&#34;&gt;&lt;ion-icon name=&#34;chevron-forward-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/ion-icon&gt;&lt;/span&gt;
        &lt;span&gt;bash&lt;/span&gt;
    &lt;/div&gt;
    &lt;div class=&#34;code-content&#34;&gt;
        
        &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 默认无需参数的情况下即会将文件下载到当前文件夹下。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 也是最常见的用法，可以加入-c避免下载中断&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wget url
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wget -O file.tgz url&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === &#34;none&#34; || codeContent.style.display === &#34;&#34;) {
        codeContent.style.display = &#34;block&#34;; 
        codeContent.parentNode.classList.remove(&#34;code-has-hidden-child&#34;);
    } else {
        codeContent.style.display = &#34;none&#34;; 
        codeContent.parentNode.classList.add(&#34;code-has-hidden-child&#34;);
    }
}
&lt;/script&gt;&lt;p&gt;参考 Man Page 或者 &lt;a href=&#34;https://www.explainshell.com/explain/1/wget&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;ExplainShell&lt;/a&gt;
 可以找到完整的参数列表；支持从文件中读取 url ；将 log 写入指定的文件等等功能；&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p>想要通过命令行直接下载文件，通常想到的就是下面的两个工具：wget 和 curl，下面简单介绍一下两者的使用。</p>
</blockquote>
<h2 id="wget">Wget</h2>
<p><code>wget</code> 全称为 <code>web get</code> ，其基本用法为：<code>wget [-para] url </code> ，常用的参数有以下几种：</p>
<ul>
<li>-O 指定下载文件的保存名称</li>
<li>-b 为后台下载模式</li>
<li>-P 下载到指定目录</li>
<li>-c 支持断电续传</li>
<li>-p 下载页面内的所有资源、包括图片视频等</li>
<li>-r 递归下载</li>
<li>-t 最大尝试次数</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 默认无需参数的情况下即会将文件下载到当前文件夹下。</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 也是最常见的用法，可以加入-c避免下载中断</span>
</span></span><span class="line"><span class="cl">wget url
</span></span><span class="line"><span class="cl">wget -O file.tgz url</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>参考 Man Page 或者 <a href="https://www.explainshell.com/explain/1/wget" target="_blank" rel="noopener">ExplainShell</a>
 可以找到完整的参数列表；支持从文件中读取 url ；将 log 写入指定的文件等等功能；</p>
<p>可以看出 wget 是一个简单，专职的下载利器，无论是用来下载安装包还是 pdf 之类的东西是一个相当方便的下载工具。</p>
<h2 id="curl">Curl</h2>
<p>参考资料：<a href="https://segmentfault.com/a/1190000022301195" target="_blank" rel="noopener">linux - wget 与 curl 命令详解 - 个人文章 - SegmentFault 思否</a>
</p>
<p><code>Curl</code> 的全称为：<code>CommandLine URL</code> 即 <code>CommandLine Uniform Resource Locator</code>，即在命令行的方式下基于 URL 的语法来进行数据或者文件的传输的工具。除了 <strong>Wget 的下载功能之外，Curl 还支持处理复杂的 web 请求，进行网络接口测试</strong>等等。</p>
<blockquote>
<p>URL 统一资源定位符</p>
</blockquote>
<h3 id="download-下载功能">Download 下载功能</h3>
<p>基本的<strong>单个文件下载功能</strong>如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl <span class="o">[</span>-o 自定义文件名<span class="o">]</span> <span class="o">[</span>-O<span class="o">]</span> <span class="o">[</span>-C 偏移量<span class="o">]</span> url
</span></span><span class="line"><span class="cl"><span class="c1"># -o 输出到指定文件</span>
</span></span><span class="line"><span class="cl"><span class="c1"># -O 以最后一个/后面的部分最为文件名</span>
</span></span><span class="line"><span class="cl"><span class="c1"># -C 偏移量，从指定的偏移量处继续下载，偏移量以字节为单位，一般用 - 代替偏移量，让其自动推算出正确的续传位置</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="web-请求处理和接口测试">WEB 请求处理和接口测试</h3>
<blockquote>
<p>该功能和 postman 是一致的，在进行前后端编写和交互的时候能起到很好的测试作用。</p>
</blockquote>
<ol>
<li>自动跳转 <code>curl -L &lt;url&gt;</code></li>
<li>显示响应头信息 <code>-i</code>，显示通信过程 <code>-v</code> ，将通信过程另存到文件 <code>--trace &lt;file&gt; &lt;url&gt;</code> 或 <code>--trace-ascii &lt;file&gt; &lt;url&gt;</code></li>
<li>指定 http 请求方式 <code>-X</code> 指定 <code>post|get|put|delete</code></li>
<li>添加 http 请求头 <code>-H 'key:value' &lt;url&gt;</code> 例如 <code>-H 'Content-Type:application/json'</code></li>
<li>设置 cookie 可以使用 <code>-b</code> 或者 <code>--cookie</code> 输入参数，或者 <code>-c 文件</code></li>
<li>设置用户名和密码 <code>-u 'user[:password]'</code></li>
<li>设置代理 <code>-A '代理信息'</code> 或者 <code>--user-agent '代理信息'</code> 也可以用 <code>-H</code> 直接设置请求头 <code>User-Agent</code></li>
<li>文件上传 <code>-F 'file=@文件'</code> 更多参数形式 <code>file=@文件;name1=value1;name2=value2</code></li>
<li>传递请求参数</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -X POST -d <span class="s1">&#39;参数&#39;</span> &lt;url&gt;</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>-d 参数会自动加上标头&quot;<code>Content-Type:application/x-www-form-urlencoded</code>&quot;，并将请求方式转为 POST。</p>
<h2 id="fi">Fi</h2>
]]></content:encoded>
    </item>
    <item>
      <title>NumpyConcatenate加速</title>
      <link>https://aikenh.cn/posts/numpyconcatenate%E5%8A%A0%E9%80%9F/</link>
      <pubDate>Sun, 02 Jul 2023 10:52:26 +0000</pubDate>
      <guid>https://aikenh.cn/posts/numpyconcatenate%E5%8A%A0%E9%80%9F/</guid>
      <description>&lt;blockquote class=&#34;alert-blockquote alert-error&#34;&gt;
  &lt;p class=&#34;alert-heading&#34;&gt;
    &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 16 16&#34; width=&#34;16&#34; height=&#34;16&#34;&gt;
      &lt;path d=&#34;M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z&#34;&gt;&lt;/path&gt;
    &lt;/svg&gt;
    &lt;span&gt;Error&lt;/span&gt;
  &lt;/p&gt;
  &lt;p&gt;多次循环进行 Numpy Concentrate 操作后，当原始数组变得过大的时，单步处理时间会逐渐变长，处理大量数据的时候时间成本极高。&lt;/p&gt;

&lt;/blockquote&gt;
&lt;h2 id=&#34;解决思路&#34;&gt;解决思路&lt;/h2&gt;
&lt;p&gt;这里简单的讲一下问题的定位过程，通过装饰器 Check 每个函数的执行时间，重点关注执行时长逐渐变长的部分。&lt;/p&gt;</description>
      <content:encoded><![CDATA[


  
  

<blockquote class="alert-blockquote alert-error">
  <p class="alert-heading">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
      <path d="M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path>
    </svg>
    <span>Error</span>
  </p>
  <p>多次循环进行 Numpy Concentrate 操作后，当原始数组变得过大的时，单步处理时间会逐渐变长，处理大量数据的时候时间成本极高。</p>

</blockquote>
<h2 id="解决思路">解决思路</h2>
<p>这里简单的讲一下问题的定位过程，通过装饰器 Check 每个函数的执行时间，重点关注执行时长逐渐变长的部分。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">time</span> <span class="kn">import</span> <span class="n">time</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">timer</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">func_wrapper</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">time_start</span> <span class="o">=</span> <span class="n">time</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="n">result</span> <span class="o">=</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">time_end</span> <span class="o">=</span> <span class="n">time</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="n">res</span> <span class="o">=</span> <span class="n">time_end</span> <span class="o">-</span> <span class="n">time_start</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;</span><span class="si">{}</span><span class="s2"> cost time: </span><span class="si">{}</span><span class="s2"> s&#34;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">func</span><span class="o">.</span><span class="vm">__name__</span><span class="p">,</span> <span class="n">res</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">result</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">func_wrapper</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>就会发现当 np.Concatenate 导致 Array 很大之后，运行就会逐渐减缓。由于运行缓慢是由于对大数组操作导致的，因此这里考虑将大数组切分成多个小数组，然后再最后进行合并。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">file</span><span class="p">,</span> <span class="s1">&#39;r&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">rf</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">	<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">rf</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="o">...</span>
</span></span><span class="line"><span class="cl">		<span class="n">new_row_array</span> <span class="o">=</span> <span class="o">...</span>
</span></span><span class="line"><span class="cl">		<span class="n">key</span> <span class="o">=</span> <span class="o">...</span>
</span></span><span class="line"><span class="cl">		<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">res_list</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">:</span>
</span></span><span class="line"><span class="cl">			<span class="n">res_list</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">new_row_array</span>
</span></span><span class="line"><span class="cl">		<span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">			<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">res_list</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span> <span class="o">&gt;=</span> <span class="n">MAX_LENGTH</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">				<span class="n">res_list</span><span class="p">[</span><span class="n">key</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">new_row_array</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">				<span class="n">res_list</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">concatenate</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">					<span class="n">res_list</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">new_row_array</span>
</span></span><span class="line"><span class="cl">				<span class="p">])</span>
</span></span><span class="line"><span class="cl">	<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">res_list</span><span class="p">)):</span>
</span></span><span class="line"><span class="cl">		<span class="n">res_list</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">concatenate</span><span class="p">(</span><span class="n">res_list</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以看上述这段代码，通过对-1 的使用，来自动的切分 Array，最后再整体合并，这样就能避免每个数组过大的问题。</p>
<p>本地实验测试也成功，将原本耗时 400s 的处理过程减少到了 30s</p>
<h2 id="fi">Fi</h2>
]]></content:encoded>
    </item>
    <item>
      <title>树莓派02 家用服务器</title>
      <link>https://aikenh.cn/posts/%E6%A0%91%E8%8E%93%E6%B4%BE%E5%AE%B6%E7%94%A8%E6%9C%8D%E5%8A%A1%E5%99%A8/</link>
      <pubDate>Sun, 02 Jul 2023 10:30:11 +0000</pubDate>
      <guid>https://aikenh.cn/posts/%E6%A0%91%E8%8E%93%E6%B4%BE%E5%AE%B6%E7%94%A8%E6%9C%8D%E5%8A%A1%E5%99%A8/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;树莓派家庭服务器的搭建以 docker 为核心，通过 docker 统一管理家庭服务，目前搭建的服务还在持续完善中，主要目的是为了方便日常使用、满足学习和探索的需求。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Docker 的安装这里不再赘述，参考 Docker Configuration01 Install on Linux 一文进行安装即可；本篇主要侧重于介绍部署的镜像和服务，以及简单介绍使用方式。&lt;/p&gt;
&lt;h2 id=&#34;一些-docker-容器推荐&#34;&gt;一些 Docker 容器推荐&lt;/h2&gt;
&lt;p&gt;这里推荐一些 Docker 容器：Alist、XiaoYa、PiDashboard、redis、mysql、portainer、memos、wikijs&lt;/p&gt;
&lt;p&gt;相关的 Docker-Compose 文件会上传到&lt;a href=&#34;https://github.com/AikenH/aikenh-DockerComposeYML&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;AikenH/aikenh-DockerComposeYML (github.com)&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id=&#34;数据库部署与远程连接测试&#34;&gt;数据库部署与远程连接测试&lt;/h2&gt;
&lt;h3 id=&#34;sqlite-3&#34;&gt;sqlite 3&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Sqlite 与 Mysql 等不同，是一个无服务器、零配置的数据库，其更像是一个解析特定数据库文件的命令接口（CLI 工具），其将数据完全存储于一个单一的跨平台磁盘文件中；&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;由于 sqlite3 的特性，决定了其是一个&lt;strong&gt;轻量级&lt;/strong&gt;且&lt;strong&gt;不需要额外配置&lt;/strong&gt;的数据库，但是在远程访问方面，只能通过文件共享来实现远程操作数据库。&lt;/p&gt;
&lt;p&gt;大多数的 Linux 系统版本都会附带 SQLite 的安装，因此我们可以直接使用下面的指令验证一下是否安装：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;div class=&#34;code-title&#34; onclick=&#34;toggleCode(this)&#34;&gt;
        
        &lt;span class=&#34;code-block-open&#34;&gt;&lt;ion-icon name=&#34;chevron-down-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/span&gt;
        &lt;span class=&#34;code-block-close&#34;&gt;&lt;ion-icon name=&#34;chevron-forward-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/ion-icon&gt;&lt;/span&gt;
        &lt;span&gt;bash&lt;/span&gt;
    &lt;/div&gt;
    &lt;div class=&#34;code-content&#34;&gt;
        
        &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sqlite3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === &#34;none&#34; || codeContent.style.display === &#34;&#34;) {
        codeContent.style.display = &#34;block&#34;; 
        codeContent.parentNode.classList.remove(&#34;code-has-hidden-child&#34;);
    } else {
        codeContent.style.display = &#34;none&#34;; 
        codeContent.parentNode.classList.add(&#34;code-has-hidden-child&#34;);
    }
}
&lt;/script&gt;&lt;p&gt;如果没有安装的话，可以去官方的&lt;a href=&#34;https://www.sqlite.org/download.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;下载页面&lt;/a&gt;
下载对应的预编译包，然后进行安装即可。&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p>树莓派家庭服务器的搭建以 docker 为核心，通过 docker 统一管理家庭服务，目前搭建的服务还在持续完善中，主要目的是为了方便日常使用、满足学习和探索的需求。</p>
</blockquote>
<p>Docker 的安装这里不再赘述，参考 Docker Configuration01 Install on Linux 一文进行安装即可；本篇主要侧重于介绍部署的镜像和服务，以及简单介绍使用方式。</p>
<h2 id="一些-docker-容器推荐">一些 Docker 容器推荐</h2>
<p>这里推荐一些 Docker 容器：Alist、XiaoYa、PiDashboard、redis、mysql、portainer、memos、wikijs</p>
<p>相关的 Docker-Compose 文件会上传到<a href="https://github.com/AikenH/aikenh-DockerComposeYML" target="_blank" rel="noopener">AikenH/aikenh-DockerComposeYML (github.com)</a>
</p>
<h2 id="数据库部署与远程连接测试">数据库部署与远程连接测试</h2>
<h3 id="sqlite-3">sqlite 3</h3>
<blockquote>
<p>Sqlite 与 Mysql 等不同，是一个无服务器、零配置的数据库，其更像是一个解析特定数据库文件的命令接口（CLI 工具），其将数据完全存储于一个单一的跨平台磁盘文件中；</p>
</blockquote>
<p>由于 sqlite3 的特性，决定了其是一个<strong>轻量级</strong>且<strong>不需要额外配置</strong>的数据库，但是在远程访问方面，只能通过文件共享来实现远程操作数据库。</p>
<p>大多数的 Linux 系统版本都会附带 SQLite 的安装，因此我们可以直接使用下面的指令验证一下是否安装：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sqlite3</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果没有安装的话，可以去官方的<a href="https://www.sqlite.org/download.html" target="_blank" rel="noopener">下载页面</a>
下载对应的预编译包，然后进行安装即可。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">wget https://www.sqlite.org/2023/sqlite-autoconf-3420000.tar.gz
</span></span><span class="line"><span class="cl">tar -zxvf sqlite-autoconf-3420000.tar.gz
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> sqlite-autoconf-3420000
</span></span><span class="line"><span class="cl">./configure --prefix<span class="o">=</span>/usr/local
</span></span><span class="line"><span class="cl">make 
</span></span><span class="line"><span class="cl">make install</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这里也提供使用 Docker-compose 安装的方式，但实际上看该数据库的特性，用 docker 安装的并不是推荐的选择。</p>
<p>参考资料：<a href="https://www.mustafabugra.com/development/sqlite-3-docker-compose/" target="_blank" rel="noopener">SQLite 3 Docker Compose – Mustafa Bugra</a>
。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;3&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">services</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">sqlite3</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">container_name</span><span class="p">:</span><span class="w"> </span><span class="l">sqlite3_container</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">nouchka/sqlite3:latest</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">stdin_open</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">tty</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="c">#Modify following line</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">path-to/your/databases/sqlite3:/root/db/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">ports</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s1">&#39;9000:9000&#39;</span><span class="w"> </span><span class="c"># expose ports - HOST:CONTAINER</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">restart</span><span class="p">:</span><span class="w"> </span><span class="l">unless-stopped</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果是树莓派的 ARM64，可能需要使用另一个<a href="https://hub.docker.com/r/keinos/sqlite3" target="_blank" rel="noopener">镜像</a>
。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker run --rm -it -v <span class="s2">&#34;</span><span class="k">$(</span><span class="nb">pwd</span><span class="k">)</span><span class="s2">:/workspace&#34;</span> -w /workspace keinos/sqlite3</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>但是该镜像的使用方式，实际上就是将其当成一个命令来用，所以还是建议本机安装。</p>
<h3 id="redis">redis</h3>
<p>使用 docker-compose 拉取指定的镜像进行安装：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;3.9&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">services</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">redis</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">redis:6.2.5</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">container_name</span><span class="p">:</span><span class="w"> </span><span class="l">docker_redis</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">privileged</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">./data:/data</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">./conf/redis.conf:/usr/local/etc/redis/redis.conf</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">./logs:/logs</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">command</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;redis-server&#34;</span><span class="p">,</span><span class="s2">&#34;/usr/local/etc/redis/redis.conf&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">ports</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="m">29005</span><span class="p">:</span><span class="m">6379</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">environment</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">TZ=&#34;Asia/Shanghai&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>设置对应的配置文件：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>conf</span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code class="language-conf" data-lang="conf">bind 0.0.0.0
# Allow Lan should be 0,0,0,0
# requirepass 123456
# need password or not
port 6379
timeout 0
save 60 10000
rdbcompression yes
dbfilename dump.rdb
dir /data
logfile &#34;redis.log&#34;</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><blockquote>
<p>这里为了方便远程连接，不设置密码，同时将 bind 设置为 0.0.0.0 允许局域网访问。</p>
</blockquote>
<p>在 Python 中测试远程连接是否正常：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">redis</span>
</span></span><span class="line"><span class="cl"><span class="n">r</span> <span class="o">=</span> <span class="n">redis</span><span class="o">.</span><span class="n">Redis</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s2">&#34;192.168.31.111&#34;</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">1234</span><span class="p">,</span> <span class="n">decode_resonses</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">r</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s2">&#34;key&#34;</span><span class="p">,</span> <span class="s2">&#34;balue&#34;</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="mysql">mysql</h3>
<p>参考文献：<a href="https://juejin.cn/post/7069365246724407327" target="_blank" rel="noopener">docker-compose 安装mysql - 掘金 (juejin.cn)</a>
  | <a href="https://www.myfreax.com/mysql-remote-access/" target="_blank" rel="noopener">配置MySQL 远程连接 | myfreax</a>
</p>
<p>使用 Docker-Compose 安装 mysql 的 docker，启用服务，设置配置文件来完成基础设置。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">version: <span class="s2">&#34;3.3&#34;</span>
</span></span><span class="line"><span class="cl">services:
</span></span><span class="line"><span class="cl">  mysql:
</span></span><span class="line"><span class="cl">    image: mysql:latest
</span></span><span class="line"><span class="cl">    environment:
</span></span><span class="line"><span class="cl">      MYSQL_ROOT_PASSWORD: <span class="s2">&#34;password&#34;</span>
</span></span><span class="line"><span class="cl">      MYSQL_USER: <span class="s1">&#39;extra-user&#39;</span>
</span></span><span class="line"><span class="cl">      MYSQL_PASS: <span class="s2">&#34;extra-password&#34;</span>
</span></span><span class="line"><span class="cl">    restart: unless-stopped
</span></span><span class="line"><span class="cl">    volumes:
</span></span><span class="line"><span class="cl">      - ./data:/var/lib/mysql
</span></span><span class="line"><span class="cl">      - ./config/my.cnf:/etc/my.cnf
</span></span><span class="line"><span class="cl">      - ./init:/docker-entrypoint-initdb.d/
</span></span><span class="line"><span class="cl">    ports:
</span></span><span class="line"><span class="cl">      - <span class="s1">&#39;29006:3306&#39;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>随便设置一个基础配置文件如下，将 Bind 地址改为 0.0.0.0 便于局域网访问</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="k">[mysqld]</span>
</span></span><span class="line"><span class="cl"><span class="na">user</span><span class="o">=</span><span class="s">mysql</span>
</span></span><span class="line"><span class="cl"><span class="na">default-storage-engine</span><span class="o">=</span><span class="s">INNODB</span>
</span></span><span class="line"><span class="cl"><span class="na">character-set-server</span><span class="o">=</span><span class="s">utf8</span>
</span></span><span class="line"><span class="cl"><span class="na">bind-address</span><span class="o">=</span><span class="s">0.0.0.0</span>
</span></span><span class="line"><span class="cl"><span class="k">[client]</span>
</span></span><span class="line"><span class="cl"><span class="na">default-character-set</span><span class="o">=</span><span class="s">utf8</span>
</span></span><span class="line"><span class="cl"><span class="k">[mysql]</span>
</span></span><span class="line"><span class="cl"><span class="na">default-character-set</span><span class="o">=</span><span class="s">utf8</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>启动服务后，进入 mysql 初始化用户密码（未设置密码前使用 mysql 命令）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mysql
</span></span><span class="line"><span class="cl"><span class="c1"># mysql -u root -p</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>初始化用户脚本，其中%为允许局域网，默认是 LocalHost，密码的引号不要删除。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">ALTER</span><span class="w"> </span><span class="k">USER</span><span class="w"> </span><span class="s1">&#39;root&#39;</span><span class="o">@</span><span class="s1">&#39;%&#39;</span><span class="w"> </span><span class="n">IDENTIFIED</span><span class="w"> </span><span class="k">WITH</span><span class="w"> </span><span class="n">mysql_native_password</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="s1">&#39;Aa123456&#39;</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以执行 show 查看当前所有的数据表，并通过 use 进入 mysql 表中，提升<a href="https://stackoverflow.com/questions/50177216/how-to-grant-all-privileges-to-root-user-in-mysql-8-0" target="_blank" rel="noopener">用户权限</a>
；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SHOW</span><span class="w"> </span><span class="n">databases</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">USE</span><span class="w"> </span><span class="n">mysql</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>具体提升权限的命令如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">CREATE</span><span class="w"> </span><span class="k">USER</span><span class="w"> </span><span class="s1">&#39;root&#39;</span><span class="o">@</span><span class="s1">&#39;%&#39;</span><span class="w"> </span><span class="n">IDENTIFIED</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="s1">&#39;PASSWORD&#39;</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">GRANT</span><span class="w"> </span><span class="k">ALL</span><span class="w"> </span><span class="k">PRIVILEGES</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="o">*</span><span class="p">.</span><span class="o">*</span><span class="w"> </span><span class="k">TO</span><span class="w"> </span><span class="s1">&#39;root&#39;</span><span class="o">@</span><span class="s1">&#39;%&#39;</span><span class="w"> </span><span class="k">WITH</span><span class="w"> </span><span class="k">GRANT</span><span class="w"> </span><span class="k">OPTION</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">FLUSH</span><span class="w"> </span><span class="k">PRIVILEGES</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>完成后可以通过 mysql 表中查看各用户的权限是否正确</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="k">host</span><span class="p">,</span><span class="w"> </span><span class="k">user</span><span class="p">,</span><span class="n">authentication_string</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="k">user</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>配置完成后即可在局域网内测试远程连接：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"> mysql -u root -ppassword -h 192.168.31.108 -P <span class="m">29006</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><blockquote>
<p>这里需要注意的是-p 和密码之间不要有空格，否则可能会提示你在输入一次密码，并表示数据表不存在。</p>
</blockquote>
<h2 id="树莓派性能检测">树莓派性能检测</h2>
<p>除了 Docker 的一系列应用之外，这里推荐移动端/mac 端的应用 ServerCat 来对 SSH 终端和 Linux 来进行性能监控，该监控无论是可视化还是连接各方面都做的十分完备。推荐。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230704133802.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230704133802.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230704133802.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230704133850.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230704133850.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230704133850.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
]]></content:encoded>
    </item>
    <item>
      <title>树莓派01 家庭影音中心</title>
      <link>https://aikenh.cn/posts/%E6%A0%91%E8%8E%93%E6%B4%BE%E5%AE%B6%E5%BA%AD%E5%BD%B1%E9%9F%B3%E4%B8%AD%E5%BF%83/</link>
      <pubDate>Wed, 28 Jun 2023 07:28:27 +0000</pubDate>
      <guid>https://aikenh.cn/posts/%E6%A0%91%E8%8E%93%E6%B4%BE%E5%AE%B6%E5%BA%AD%E5%BD%B1%E9%9F%B3%E4%B8%AD%E5%BF%83/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;将 RaspBerry Pi 4B 作为家庭影视中心/机顶盒的核心就是 KODI 软件，这是考虑到以下的几点：遥控器的控制、对挂载 webdav 和其他的支持&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最方便的方式可以选择以 KODI 为核心的两个 OS：LibreELEC、OSMC（推荐），这两个系统以 KODI 为默认启动，同时也支持远程登录和 Docker 部署等 Linux 的功能。后者更为推荐应该是前者的官方改进版本。&lt;/p&gt;
&lt;p&gt;考虑到后续可能会将该 SD 卡用于其他用处，因此本文选择的是使用 RaspBerryPi OS 的方案，以下围绕该方案进行展开：&lt;/p&gt;
&lt;h2 id=&#34;raspberry-pi-oskodialist-方案探究&#34;&gt;RaspBerry Pi OS+Kodi+Alist 方案探究&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;可以参考 trouble shooting，可以发现实际上安装 kodi 最简单的方式就是直接使用 apt，无需做其他的 PPA 添加。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;安装kodi&#34;&gt;安装Kodi&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;div class=&#34;code-title&#34; onclick=&#34;toggleCode(this)&#34;&gt;
        
        &lt;span class=&#34;code-block-open&#34;&gt;&lt;ion-icon name=&#34;chevron-down-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/span&gt;
        &lt;span class=&#34;code-block-close&#34;&gt;&lt;ion-icon name=&#34;chevron-forward-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/ion-icon&gt;&lt;/span&gt;
        &lt;span&gt;bash&lt;/span&gt;
    &lt;/div&gt;
    &lt;div class=&#34;code-content&#34;&gt;
        
        &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install kodi&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === &#34;none&#34; || codeContent.style.display === &#34;&#34;) {
        codeContent.style.display = &#34;block&#34;; 
        codeContent.parentNode.classList.remove(&#34;code-has-hidden-child&#34;);
    } else {
        codeContent.style.display = &#34;none&#34;; 
        codeContent.parentNode.classList.add(&#34;code-has-hidden-child&#34;);
    }
}
&lt;/script&gt;&lt;p&gt;安装完后，使用 kodi 命令开启或者在开始菜单的软件中心中选择 kodi 打开。&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p>将 RaspBerry Pi 4B 作为家庭影视中心/机顶盒的核心就是 KODI 软件，这是考虑到以下的几点：遥控器的控制、对挂载 webdav 和其他的支持</p>
</blockquote>
<p>最方便的方式可以选择以 KODI 为核心的两个 OS：LibreELEC、OSMC（推荐），这两个系统以 KODI 为默认启动，同时也支持远程登录和 Docker 部署等 Linux 的功能。后者更为推荐应该是前者的官方改进版本。</p>
<p>考虑到后续可能会将该 SD 卡用于其他用处，因此本文选择的是使用 RaspBerryPi OS 的方案，以下围绕该方案进行展开：</p>
<h2 id="raspberry-pi-oskodialist-方案探究">RaspBerry Pi OS+Kodi+Alist 方案探究</h2>
<blockquote>
<p>可以参考 trouble shooting，可以发现实际上安装 kodi 最简单的方式就是直接使用 apt，无需做其他的 PPA 添加。</p>
</blockquote>
<h3 id="安装kodi">安装Kodi</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt-get install kodi</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>安装完后，使用 kodi 命令开启或者在开始菜单的软件中心中选择 kodi 打开。</p>
<h3 id="设置-gpu-显存硬解相关">设置 GPU 显存（硬解相关）</h3>
<p>首先做一下<strong>固件的升级</strong>：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo rpi-update</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>然后<strong>调整一下显存</strong>：系统设置里面将 gpu_mem 调高一些，我使用的是 4G，调整到了 256MB，切记不要调整太高，否则可能会开机失败，重启后查看显存是否设置成功。</p>
<p><strong>查看 GPU 显存</strong>的方式：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">vcgencmd get_mem arm <span class="o">&amp;&amp;</span> vcgencmd get_mem gpu</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>最后在 kodi 中查看相关的选项的开关情况：</p>
<p>参考资料：<a href="https://www.liujason.com/article/656.html" target="_blank" rel="noopener">树莓派RaspberryPi 4B设置显存开启硬件加速 支持Emby|Plex|JellyFin转码 LiuJason&rsquo;sBlog</a>
</p>
<h3 id="kodi-界面设置中文">KODI 界面设置（中文）</h3>
<p>里面 Interface 选项 -&gt; 皮肤 -&gt; 字体选择 Arial（支持中文，不然会乱码）</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230701092809.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230701092809.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230701092809.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>如果皮肤下面没有字体的子项，可以选择切换左下角的模式，切换到专家就可看到</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230701093132.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230701093132.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230701093132.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>切换完字体，选择皮肤下面的区域 Region-&gt; Language -&gt; Chinese 即可。</p>
<h3 id="kodi-添加-webdav">KODI 添加 WebDav</h3>
<p>首先选择资料库中的进入文件区 -&gt; 添加视频 -&gt; 添加视频源处选择浏览 -&gt; 添加网络位置处</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230701093315.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230701093315.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230701093315.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ul>
<li>如果是本地挂载的协议一般选择 HTTP，服务器地址填写局域网 IP 即可，远程路径填写 Dav，端口是设定好的端口；</li>
<li>如果是远程的一些 Alist 网站，可以选择 WebDav 的 HTTPs ，其他的参考相关网站给出的设置即可。</li>
</ul>
<p>本地就一葫芦画瓢就行，添加完后可以看到相关的源，然后选择文件夹和对应显示的名称即可，需要注意的是，这里我们最好不启用刮削服务（Alist 等网盘的情况下），避免被封号等一系列问题。</p>
<h3 id="kodi-设置-iptv-播放">Kodi 设置 iptv 播放</h3>
<p>kodi 支持 iptv 播放主要依赖于<strong>PVR IPTV Simple Client</strong> 插件，通过该插件设置 m3u 直播源即可实现 iptv 的播放。</p>
<p><strong>PVR IPTV Simple Client</strong>的几种安装方法：</p>
<ol>
<li>kodi 直接询问是否启用；</li>
<li>kodi-&gt;设置-&gt;插件-&gt;从库安装-&gt;pvr clients-&gt; <strong>PVR IPTV Simple Client</strong></li>
<li>如果上述两个方法都失效，使用插件中的从 zip 安装，相关的 zip 文件可以从此处安装：<a href="http://www.kodiplayer.cn/plugins/2969.html" target="_blank" rel="noopener">Kodi中文网</a>
</li>
</ol>
<p>安装后在插件的设置目录中，设置 m3u 的获取方式是本地文件还是 url 即可。</p>
<p>设置完成后可在首页的 TV 观看电视直播，iptv 源的获取参照 <a href="https://aikenh.cn/cn/alist_potplayer/#Iptv-%E5%88%97%E8%A1%A8" target="_blank" rel="noopener">Windows App01 Potplayer &amp; Alist</a>
 一文中的 iptv 列表获取。</p>
<h3 id="kodi-手机遥控器设置和添加">KODI 手机遥控器设置和添加</h3>
<p>手机端直接下载 Kodi remote control ，参考设置进行配置即可</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230701100221.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230701100221.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230701100221.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230701100227.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230701100227.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230701100227.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>这里可能需要设置以下用户名和密码，来允许 HTTP 控制。</p>
<h3 id="树莓派投屏方案">树莓派投屏方案</h3>
<blockquote>
<p>根据 kodi 的 wiki 已知其已经不支持 ios8 以上的 Airplay 功能，因此针对投屏的需求，只能通过视频软件或者播放器的 UpnP/DLNA 支持进行投屏。</p>
</blockquote>
<ul>
<li>在 kodi 的设置界面-&gt;服务-&gt;UpnP/DLNA 中选择启用的相关选项</li>
<li>在 ios 中设置-&gt;对应的视频软件（如bilibili）-&gt;本地网络选择启用</li>
</ul>
<p>播放视频时左上角 tv 的按钮，并选中本地局域网中的 kodi 即可。</p>
<h2 id="trouble-shooting-问题解决">Trouble Shooting 问题解决</h2>
<h3 id="kodi-官方教程安装失败原因及解决">Kodi 官方教程安装失败原因及解决</h3>
<p><strong>问题描述与分析</strong></p>
<p>尝试了 <strong>Ubuntu22.04+RaspBerry 4B+Kodi+Alist</strong> 的方案，发现这种方案<strong>遵循官方教程</strong>无法在 Ubuntu 中成功的安装 Kodi，成功安装后出现以下的问题：</p>
<ul>
<li>command not found</li>
<li>无对应的 desktop app</li>
<li>desktop app 无法打开</li>
</ul>
<p>该原因是由于<strong>基于官方PPA</strong>在 <strong>Ubuntu 上安装的 Kodi 似乎无法在 RaspBerry 的架构</strong>上执行，因此无法成功安装，具体可以参考如下的几个连接，其中的讨论对该原因也会有所讲解。</p>
<ul>
<li><a href="https://forums.raspberrypi.com/viewtopic.php?t=312797" target="_blank" rel="noopener">Has anyone got kodi working on ubuntu 21.04 - Raspberry Pi Forums</a>
</li>
<li><a href="https://www.reddit.com/r/kodi/comments/nmpcbl/kodi_for_ubuntu_raspberry_pi_version/" target="_blank" rel="noopener">KODI for Ubuntu Raspberry Pi version : r/kodi (reddit.com)</a>
</li>
</ul>
<p>同时<a href="https://kodi.wiki/view/HOW-TO:Install_Kodi_for_Linux#Adding_Team_Kodi_PPA_repository" target="_blank" rel="noopener">官方</a>
指出，这种方式不适用于 armhf，（似乎 raspberry 4b 的 arm64 也无法执行</p>
<blockquote>
<p>Note that this PPA only provides builds for Ubuntu i386 and Ubuntu amd64 but <em>not for Ubuntu armhf</em>, which can run on a Raspberry Pi.</p>
</blockquote>
<p>可以以此<strong>查看系统的架构</strong>：<a href="https://www.coonote.com/note/linux-amd-arm.html" target="_blank" rel="noopener">查看linux系统是哪种架构：AMD、ARM、x86、x86_64、pcc 或 查看Ubuntu的版本号-菜鸟笔记 (coonote.com)</a>
</p>
<p><strong>架构间的区别</strong>如下：<a href="https://forum.cloudreve.org/d/1855" target="_blank" rel="noopener">安装包amd,amd64,arm,arm64都有什么区别？ - Cloudreve Forum</a>
</p>
<blockquote>
<ol>
<li>amd64是 X86架构的 CPU，64位版。amd64又叫 X86_64。主流的桌面 PC，笔记本电脑，服务器（包括虚拟机）都在用 X86_64的 CPU。</li>
<li>arm64是 ARM 架构的 CPU，64位版。苹果新出的电脑在用 ARM 架构的 CPU。有些路由器和嵌入式设备在用 arm64的 CPU。手机和安卓平板电脑最常用的 CPU 也是 ARM 架构的。</li>
<li>MIPS 是 MIPS 架构的 CPU。有些嵌入式设备和家用路由器在用 MIPS 架构的 CPU。</li>
</ol>
</blockquote>
<p>简单的说就是：</p>
<ul>
<li>AMD64=linux-64bit=X86</li>
<li>ARM64=linux- <a href="https://so.csdn.net/so/search?q=Aarch64&amp;spm=1001.2101.3001.7020" target="_blank" rel="noopener">Aarch64</a>
 =ARM</li>
</ul>
<blockquote>
<p>Aarch 指的就是 <a href="https://so.csdn.net/so/search?q=ARM&amp;spm=1001.2101.3001.7020" target="_blank" rel="noopener">ARM</a>
 architecture</p>
</blockquote>
<p><strong>解决方案</strong></p>
<p>发现是架构不匹配的原因导致的时候，去查询相关的源是否有对应架构的安装包：<a href="https://pkgs.org/download/kodi" target="_blank" rel="noopener">Kodi Download (APK, DEB, EOPKG, PKG, RPM, TXZ, XBPS, ZST) (pkgs.org)</a>
 找到了 Arm64 的版本</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230628080044.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230628080044.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230628080044.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>但是进去看可以发现实际上该安装还是指向了官方 PPA，安装的 ARCH 描述为 ALL（not true），不过好在后面有别的选项：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230628080303.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230628080303.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230628080303.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>找到下面的 arm64 的版本，详情页就能找到下载说明，由于是官方软件源，只需要 apt 安装就行，前提是将之前安装的会导致错误版本的 PPA 源卸载干净。</p>
<blockquote>
<p>可以到/etc/apt/sources.list.d/检查并将不需要的软件源删掉，再 sudo apt-get update 一下</p>
</blockquote>
<h3 id="ubuntu-播放-4k-视频卡顿掉帧">Ubuntu 播放 4k 视频卡顿掉帧</h3>
<p>这部分可能是由于 Ubuntu 和 RaspBerryPi 一起用的时候，对于硬件的控制比较麻烦，导致功能中的<strong>硬解没有开启</strong>的地方导致，而在后续开启 Ubuntu 22.04 硬解的时候，需要去修改 Bios 文件，导致我这边系统损坏了无法开机，就没有做进一步的测试。</p>
<blockquote>
<p>20.04 和之前的版本有找到对应的文档， 22.04 好像暂时没有，参考之前的方案进行修改的时候出现了开机损坏的情况，所以还是要慎重。</p>
</blockquote>
<p><strong>检查硬解是否启用</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cat /proc/device-tree/soc/firmwarekms@7e600000/status
</span></span><span class="line"><span class="cl">cat /proc/device-tree/v3dbus/v3d@7ec04000/status</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>设置的参考资料：<a href="https://www.dedoimedo.com/computers/rpi4-ubuntu-mate-hw-video-acceleration.html" target="_blank" rel="noopener">RPI4 &amp; Ubuntu MATE - How to enable video acceleration (dedoimedo.com)</a>
</p>
<h3 id="树莓派-hdmi-热插拔">树莓派 HDMI 热插拔</h3>
<blockquote>
<p>树莓派的 HDMI 接口在长时间未使用，或者在开机的时候未连接显示器的时候，会默认以无显示输出的情况启动，导致电视无法正常输出图像。</p>
</blockquote>
<p>为此，我们需要开启设置中的 <code>hdmi_force_hotplug=1</code>，无论是否检测到 Hdmi 显示器，都默认有 hdmi 连接，确保无需每次需要视频输出的时候都重启树莓派，具体的操作步骤如下：</p>
<blockquote>
<p>适用于 RaspBerryPi OS</p>
</blockquote>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">vim /boot/config.txt <span class="c1"># 默认配置文件的地址</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果不在该地址，就需要找到启动分区所在的目录，应该在该目录下，找到该文件后修改将以下两项打开或新增之后重启树莓派即可；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">hdmi_force_hotplug=1  
</span></span><span class="line"><span class="cl">hdmi_drive=2</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li><code>hdmi_force_hotplug=1</code> 设置树莓派使用 HDMI 热插拔模式，即使没有检测到 HDMI 显示器。</li>
<li><code>hdmi_drive=2</code> 将树莓派设置为正常的 HDMI 模式（如果支持和启用，将发送声音）。如果没有这条线，树莓派将默认切换到 DVI（无音频）模式。</li>
</ul>
<p>但是热插拔的情况下，可能会导致在最终使用 hdmi 输出的时候，树莓派自动设定的分辨率不符合我们的使用和设备预期，因此我们可能还要基于设备对树莓派的分辨率和输出模式做一个限制；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">hdmi_group=1
</span></span><span class="line"><span class="cl">hdmi_mode=16</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li><code>hdmi_group</code> 指定分辨率格式1为 CEA，电视规格的分辨率；2为 DMT，计算机显示器使用的分辨率</li>
<li><code>hdmi_mode</code> 不同分辨率格式下的指定分辨率和刷新率情况，具体可以见表</li>
</ul>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230803091910.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230803091910.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230803091910.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="kodi-从配置文件切换主题">Kodi 从配置文件切换主题</h3>
<p>由于 kodi 版本不一和兼容性等等各种问题的原因，有时候安装并启用了某些主题可能会导致 kodi 频繁崩溃无法操作的情况，这种情况下我们只需要在命令行中对主题进行修改，将其改为默认主题后再启动 kodi 卸载有问题的主题即可。</p>
<p>kodi 主题配置文件的地址在：<code>~/.kodi</code> 中的 <code>「文件」</code>，如果不记得了简单的 grep 以下当前使用的主题即可，所以建议每次安装新主题的时候记住主题的部分字段。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">grep -rliI <span class="s2">&#34;theme name&#34;</span> ~/.kodi
</span></span><span class="line"><span class="cl">grep -rniI <span class="s2">&#34;theme namøe&#34;</span> ~/.kodi</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这里可以使用-l 命令只显示匹配到的文件，-i 忽略大小写，-I 忽略二进制文件，-r 递归匹配，-n 显示行号；</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231102132540.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231102132540.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231102132540.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>如上图所示，在此处可以修改启动的时候使用的皮肤，对应的代码位于如下的地方，仿照该形式进行修改即可。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231102132627.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231102132627.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20231102132627.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>参考资料：</p>
<ul>
<li><a href="https://www.cyandragon.net/?p=471" target="_blank" rel="noopener">解决树莓派不接HDMI导致开机VNC无信号问题和分辨率不对问题 – CyanDragon</a>
</li>
<li><a href="https://likfe.com/2021/12/19/raspberry-pi-hdmi/" target="_blank" rel="noopener">树莓派配置文件 config.txt - HDMI 热插拔 | Cafeting (likfe.com)</a>
</li>
<li><a href="https://shumeipai.nxez.com/2013/08/31/custom-display-resolution-raspberry-pie.html" target="_blank" rel="noopener">自定义树莓派的显示分辨率 | 树莓派实验室 (nxez.com)</a>
</li>
<li><a href="https://cloud-atlas.readthedocs.io/zh_CN/latest/arm/raspberry_pi/display/pi_hdmi.html" target="_blank" rel="noopener">树莓派HDMI配置 — Cloud Atlas 0.1 文档 (cloud-atlas.readthedocs.io)</a>
</li>
</ul>
<h2 id="fi">FI</h2>
]]></content:encoded>
    </item>
    <item>
      <title>Windows Clash局域网代理共享</title>
      <link>https://aikenh.cn/posts/%E5%B1%80%E5%9F%9F%E7%BD%91%E4%BB%A3%E7%90%86%E5%85%B1%E4%BA%AB/</link>
      <pubDate>Thu, 22 Jun 2023 10:41:25 +0000</pubDate>
      <guid>https://aikenh.cn/posts/%E5%B1%80%E5%9F%9F%E7%BD%91%E4%BB%A3%E7%90%86%E5%85%B1%E4%BA%AB/</guid>
      <description>使用Clash作为局域网中的代理服务器</description>
      <content:encoded><![CDATA[<blockquote>
<p>本文介绍基于 Windows Clash Desktop 的代理服务器设置，可以为局域网内的设备提供代理服务，该方案可以解决一定的科学上网需求，但是没办法覆盖所有的场景，例如 PS5 的 Netflix ，其不走代理服务器，因此无法通过该方案解决，（软路由可破）</p>
</blockquote>
<p>本篇的设置内容主要会从两个方面出发：一个是服务器的开启和防火墙的设置、另一个是客户端如何设置使用对应的代理服务器。</p>
<h2 id="clash开启代理服务器">Clash开启代理服务器</h2>
<p>Clash 作为局域网代理服务器开启的方式十分简单，主要是以下几步。</p>
<blockquote>
<p>开启局域网访问 -&gt; 设置端口，查看 ip -&gt;  防火墙允许通行</p>
</blockquote>
<h3 id="配置代理服务器">配置代理服务器</h3>
<p><strong>开启局域网访问</strong>： Allow LAN 打钩即可。
<strong>端口</strong>：设置好想要的 mixport 即可。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230626091350.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230626091350.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230626091350.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><strong>防火墙允许通行</strong>： 防火墙-&gt; 高级设置，找到 Clash 所有项，允许其在专用网络上通行。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230626091506.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230626091506.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230626091506.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>

<strong>查看 ip</strong>：命令行输入 <code>ipconfig/ all</code> 里面的 WLAN 模块，可以找到自己的局域网 ip</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230626091742.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230626091742.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230626091742.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="一些坑-troubleshoot">一些坑 TroubleShoot</h3>
<ul>
<li>这一部分主要的问题在于，防火墙这一步很多地方都没有提到，这样会导致 Clash 被防火墙拦截，客户端就无法找到代理服务器，导致设置代理服务器后（比如 IOS），显示 WIFI 异常，无法访问网络的问题。</li>
<li>有一些相关的资料表示，如果连接失败，也有可能是 server 服务和 TAp 服务的原因，将两个服务卸载后在尝试即可。（这一部分我没有遇到）</li>
</ul>
<h2 id="客户端设置代理服务器">客户端设置代理服务器</h2>
<p>这里介绍一下 IOS 设置代理服务器的步骤，Ubuntu 等桌面系统（包含网络设置的）设置步骤都是差不多的，</p>
<h3 id="实例ios">实例：IOS</h3>
<p>在 Wifi 链接的详细信息界面，选择配置代理服务器</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230622110612.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230622110612.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230622110612.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>进入设置页后，改为手动，输入我们设置好的代理服务器的 IP 和对应的端口即可。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230622110722.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230622110722.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230622110722.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>设置完成后连接至该 WiFi 即可。</p>
]]></content:encoded>
    </item>
    <item>
      <title>Docker Configuration01 Install on Linux</title>
      <link>https://aikenh.cn/posts/%E5%9C%A8linux%E4%B8%AD%E5%AE%89%E8%A3%85docker/</link>
      <pubDate>Thu, 22 Jun 2023 09:25:29 +0000</pubDate>
      <guid>https://aikenh.cn/posts/%E5%9C%A8linux%E4%B8%AD%E5%AE%89%E8%A3%85docker/</guid>
      <description>install docker on linux with portainer</description>
      <content:encoded><![CDATA[<p>不同于 Docker 在 Windows 端借助 Desktop 可视化进行安装和配置，Linux 端没有默认的 Desktop 界面，因此会额外安装 portainer 作为我们 docker 的 Dashboard.</p>
<h2 id="install-docker-on-ubuntu">Install Docker on Ubuntu</h2>
<blockquote>
<p>该部分完全转载自<a href="https://docs.docker.com/engine/install/raspbian/" target="_blank" rel="noopener">官方</a>
的安装指引，如果流程需要更新的时候可以移步官网检查，此外官网还包含了其他几种安装方式，这里就不介绍，这里只介绍基于 apt 的安装方式。</p>
</blockquote>
<h3 id="设置-apt-的-repo">设置 apt 的 repo</h3>
<p>1 更新 apt 的索引，同时通过下载包来允许 Apt 基于 http 来索引仓库</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt-get update
</span></span><span class="line"><span class="cl">sudo apt-get install ca-certificates curl gnupg</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>2 安装 docker 官方的 GPG 秘钥</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo install -m <span class="m">0755</span> -d /etc/apt/keyrings
</span></span><span class="line"><span class="cl">curl -fsSL https://download.docker.com/linux/ubuntu/gpg <span class="p">|</span> sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
</span></span><span class="line"><span class="cl">sudo chmod a+r /etc/apt/keyrings/docker.gpg</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>3 配置对应的 repository</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  <span class="s2">&#34;deb [arch=&#34;</span><span class="k">$(</span>dpkg --print-architecture<span class="k">)</span><span class="s2">&#34; signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
</span></span></span><span class="line"><span class="cl"><span class="s2">  &#34;</span><span class="k">$(</span>. /etc/os-release <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$VERSION_CODENAME</span><span class="s2">&#34;</span><span class="k">)</span><span class="s2">&#34; stable&#34;</span> <span class="p">|</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  sudo tee /etc/apt/sources.list.d/docker.list &gt; /dev/null</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>完成上述设置之后，就可以开始安装 Docker 了。</p>
<h3 id="安装-docker-engine">安装 docker-engine</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 更新apt索引</span>
</span></span><span class="line"><span class="cl">sudo apt-get update
</span></span><span class="line"><span class="cl">sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="查看是否安装成功">查看是否安装成功</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker -v
</span></span><span class="line"><span class="cl">docker-compose -v 
</span></span><span class="line"><span class="cl">docker compose version</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>（待验证）理论上安装了 docker-compose-plugin 后，应该是已经成功安装了 compose，如果没有的话，可以尝试用下列命令来安装。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt-get install docker-compose</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="测试服务是否能正常使用">测试服务是否能正常使用</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo docker run hello-world</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>通过 hello-world 项目测试 docker 的拉取、构建、运行是否存在问题，通常来说正常安装之后，镜像是能正常的启动，可能出现问题的大多是网络部分，也就是 Pull 的环节，这个环节出问题，通常可以使用两种方式来解决：代理设置/ 换源。</p>
<h2 id="install-docker-on-raspberrypi">Install Docker on RaspberryPi</h2>
<p>参考官方的安装指令，下载官方提供的安装脚本进行安装，安装完后按照 Ubuntu 中的方式同样校验即可。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -fsSL https://get.docker.com -o get-docker.sh
</span></span><span class="line"><span class="cl">sudo sh get-docker.sh
</span></span><span class="line"><span class="cl"><span class="c1"># can add --dry-run to know what step we invoked</span>
</span></span><span class="line"><span class="cl"><span class="c1"># sudo sh ./get-docker.sh --dry-run</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>简单便捷</p>
<h2 id="source-change-or-proxy-setup">Source Change or Proxy Setup</h2>
<p>科学上网为了科学，通过换源或设置代理来加速镜像拉取，避免镜像拉取产生的问题，镜像拉取 docker pull 在 docker 中实际上是 daemon 及守护进程执行的，因此主要修改的是其相关设置部分。</p>
<p>参考资料：<a href="https://www.jianshu.com/p/b4a6239712bf" target="_blank" rel="noopener">docker更换镜像源</a>
 | <a href="https://yeasy.gitbook.io/docker_practice/advanced_network/http_https_proxy" target="_blank" rel="noopener">配置 HTTP/HTTPS 网络代理 - Docker从入门到实践 </a>
</p>
<h3 id="换源-source-change">换源 Source Change</h3>
<p>打开配置文件：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">vim /etc/docker/daemon.json</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>添加镜像源相关设置（添加如下内容）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>json</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;registry-mirrors&#34;</span> <span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;https://registry.docker-cn.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;http://hub-mirror.c.163.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;https://docker.mirrors.ustc.edu.cn&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;https://cr.console.aliyun.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;https://mirror.ccs.tencentyun.com&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>配置完使用的所有镜像源后，即可重启 docker 来实现换源：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo systemctl daemon-reload
</span></span><span class="line"><span class="cl">sudo systemctl restart docker.service</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>使用 docker info 查看配置是否成功：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo docker info</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在为 Ubuntu 的网络添加代理设置后，换源操作没有解决我无法 pull 相关镜像的问题，后续通过设置了 daemon 也使用代理解决了镜像拉取的问题。</p>
<h3 id="代理配置-proxy-setup">代理配置 Proxy Setup</h3>
<blockquote>
<p>&ldquo;docker pull&rdquo; 命令是由 dockerd 守护进程执行。而 dockerd 守护进程是由 systemd 管理。因此，如果需要在执行 &ldquo;docker pull&rdquo; 命令时使用 HTTP/HTTPS 代理，需要通过 systemd 配置</p>
</blockquote>
<p>Docker 在拉取、构建、运行三个阶段中，代理的配置是相互独立互不影响的，如果我们希望某个阶段中使用相应的代理，就需要分别进行配置，这里主要介绍的是镜像拉取环节使用的代理，其他部分的代理设置也可以在参考文章中找到。</p>
<p>A. 为 docker 创建对应的配置文件夹</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mkdir -p /etc/systemd/system/docker.service.d</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>B. 创建代理相关的配置文件，并填入代理相关信息，配置文件的路径为：<code>/etc/systemd/system/docker.service.d/http-proxy.conf</code></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">vim /etc/systemd/system/docker.service.d/http-proxy.conf</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>C. 填入相关的代理信息：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="k">[Service]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="na">Environment</span><span class="o">=</span><span class="s">&#34;HTTP_PROXY=http://192.168.157.231:7890/&#34;</span>
</span></span><span class="line"><span class="cl"><span class="na">Environment</span><span class="o">=</span><span class="s">&#34;HTTPS_PROXY=http://192.168.157.231:7890&#34;</span>
</span></span><span class="line"><span class="cl"><span class="na">Environment</span><span class="o">=</span><span class="s">&#34;NO_PROXY=localhost,127.0.0.1,.example.com&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>D. 服务重启</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo systemctl daemon-reload
</span></span><span class="line"><span class="cl">sudo systemctl restart docker</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>E. 查看是否配置成功</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo docker info</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>通常来说只要代理服务器正常运行，到这里应该就可以解决镜像拉取不下来的问题了，接下来为 Docker 安装一个 Dashboard 便于我们查看 Container 的运行情况，以及进行简单的修改等。</p>
<h2 id="install-portainer-for-docker">Install Portainer for Docker</h2>
<p>参考资料：<a href="https://zhuanlan.zhihu.com/p/521563945" target="_blank" rel="noopener">Docker环境5分钟快速部署Portainer-ZHIHU</a>
</p>
<p>这里我们使用 docker-compose 安装 portainer，实际上 docker-compose 实际上就是将 docker 的运行指令写成一个 yml 文件的形式，个人偏好这种方式，这种方式更方便对执行指令的掌握和查看，而且便于长期管理。</p>
<p>首先随便创建一个目录来存放对应的数据和配置：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mkdir -p ~/workspace/docker-compose-dir/portainer
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> ~/workspace/docker-compose-dir/portainer
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">touch docker-compose.yml
</span></span><span class="line"><span class="cl">vim docker-compose.yml</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>编写对应的 docker-compose 文件如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;3&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">services</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">portainerce</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">portainer/portainer-ce:latest</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">container_name</span><span class="p">:</span><span class="w"> </span><span class="l">portainerce</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">restart</span><span class="p">:</span><span class="w"> </span><span class="l">unless-stopped</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">security_opt</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="kc">no</span>-<span class="l">new-privileges:true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">/etc/localtime:/etc/localtime:ro</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">/var/run/docker.sock:/var/run/docker.sock:ro</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">./portainer-data:/data</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">ports</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="m">9000</span><span class="p">:</span><span class="m">9000</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在当前目录执行指令，启动安装和构建</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker-compose up -d</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>执行后我们即可访问：<code>localhost:9000</code> 进入 portainer ，首次进入需要设置一个管理员账户，设置完成后即可，</p>
<h2 id="fi">FI</h2>
<p>完成了上述设置之后，就可以开始用 docker 拉取和构建自己需要的镜像了，对于 NAS，树莓派，服务器，各种东西都可以开始愉快的玩耍了。</p>
]]></content:encoded>
    </item>
    <item>
      <title>Terminal multiplexer Zellij</title>
      <link>https://aikenh.cn/posts/linuxzellij/</link>
      <pubDate>Sat, 20 May 2023 16:40:19 +0000</pubDate>
      <guid>https://aikenh.cn/posts/linuxzellij/</guid>
      <description>It is recommended to replace tmux with zellij</description>
      <content:encoded><![CDATA[<blockquote>
<p>Tmux 作为一款优秀的终端复用器，前面已经介绍过，这里在介绍一款有着相同功能的平替，个人认为 zellij 的 UI 各方面的设计，使得其相比于 Tmux 有着更低的入门难度，也避免了需要记大量快捷键，因此这里介绍一下该工具。</p>
</blockquote>
<p><a href="https://zellij.dev/documentation/installation.html" target="_blank" rel="noopener">Zellij</a>
 是一款终端复用器，有什么功能可以完全参考 Tmux ，还支持了许多有趣的特性和自定义 Layout 等功能（可能后续用到的话会完善该部分笔记），详细的可以参考官网的介绍，接下来就简单的介绍一下安装和一些自定义的 Alias。</p>
<h2 id="install-安装">Install 安装</h2>
<p>Zellij 是基于 Rust 编写，因此在安装之前需要安装 rust 和 cargo（类似 rust 的包管理器），安装可以参考 <a href="https://www.rust-lang.org/tools/install" target="_blank" rel="noopener">Rust 官方网站（推荐）</a>
 |  <a href="https://doc.rust-lang.org/cargo/getting-started/installation.html" target="_blank" rel="noopener">The Cargo Book</a>
  | <a href="https://rustwiki.org/zh-CN/cargo/getting-started/installation.html" target="_blank" rel="noopener">Rust Wiki CN</a>
</p>
<p>官方网站中介绍了 WSL 的安装指令如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl --proto <span class="s1">&#39;=https&#39;</span> --tlsv1.2 -sSf https://sh.rustup.rs <span class="p">|</span> sh
</span></span><span class="line"><span class="cl"><span class="c1">#--proto以及--tlsvl在Linux或者Macos安装的时候可以忽略</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>安装完成后可以使用如下命令，基于 Cargo 安装 zellij：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cargo install --locked zellij</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果出现了问题也可以尝试先更新 rust</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">rustup update</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="binary-download-二进制文件安装下载">Binary Download 二进制文件安装下载</h3>
<p>如果是<strong>不便于安装</strong>的环境可以使用这种方式来使用 zellij，在 <a href="https://github.com/zellij-org/zellij/releases" target="_blank" rel="noopener">release page</a>
 中下载二进制包 <code>.tar.gz</code> 后执行：</p>
<p>解压二进制文件：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">tar -xvf zellij*.tar.gz</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>修改执行权限：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">chmod +x zellij</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>然后就可以直接执行 zellij 文件了，可以将该文件路径<a href="https://www.baeldung.com/linux/path-variable" target="_blank" rel="noopener">加入系统的路径</a>
中，即可随处调用（也可以使用 alias 的方式），可以参考一下上文中系统路径的添加方法。</p>
<h2 id="alias-别名设置">Alias 别名设置</h2>
<p>由于 Zellij 的一些指令比较长，可以简单的设置一下别名（bashrc, zshrc），用来便于日常使用：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">ze</span><span class="o">=</span><span class="s1">&#39;zellij&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">zels</span><span class="o">=</span><span class="s1">&#39;zellij list-sessions&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">zeks</span><span class="o">=</span><span class="s1">&#39;zellij kill-sessions&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">zeat</span><span class="o">=</span><span class="s1">&#39;zellij attach&#39;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以看出上述的指令和 Tmux 的十分相似，功能也和名称一致，这里就不在赘述，其他的使用快捷键在进入了 zellij 界面后都可以看到。</p>
<h3 id="效果展示">效果展示</h3>
<p>简单放一下 zellij 使用的效果图，相信能 Get 到为啥说比较容易上手，同时 UI 也十分的舒服。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230520170858.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230520170858.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230520170858.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230520170932.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230520170932.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230520170932.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="fi">FI</h2>
<p>基础的功能对于日常使用已经十分充分，后续又其他的功能需求（如果有自己定制的东西）的话会慢慢更新，否则的话应该就是基于官方文档去配置和使用了。</p>
]]></content:encoded>
    </item>
    <item>
      <title>AIGC05 Stable Diffusion Model Training</title>
      <link>https://aikenh.cn/posts/stablediffusiontraining/</link>
      <pubDate>Sat, 06 May 2023 23:43:41 +0000</pubDate>
      <guid>https://aikenh.cn/posts/stablediffusiontraining/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;该章节主要介绍 Stable-Diffusion 中模型的训练，考虑到硬件条件的限制，实际上这里介绍的训练，都是针对大模型的各种微调技术（Lora，Dreambooth，HyperNetwork, &amp;hellip;），这里会以 LoRA 模型的训练为主。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;参考文献：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.gamelook.com.cn/2023/04/514936&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;AIGC教程：Stable Diffusion精进，如何训练特定画风LoRA模型？ | 游戏大观 | GameLook.com.cn&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.cnblogs.com/wangiqngpei557/p/17301360.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;stable diffusion打造自己专属的LORA模型 - 王清培 - 博客园 (cnblogs.com)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/kohya-ss/sd-scripts/blob/main/train_README-zh.md&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;sd-scripts/train_README-zh.md at main · kohya-ss/sd-scripts · GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;train-lora&#34;&gt;Train LoRA&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;LoRA 的优势就是其模型更小，且更加模块化；也就是说其的训练成本和要求都更低，同时使用代价小，可以作为某种风格插件或者角色插件来使用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://huggingface.co/blog/zh/lora&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;使用 LoRA 进行 Stable Diffusion 的高效参数微调 (huggingface.co)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://arxiv.org/abs/2106.09685&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;[2106.09685] LoRA: Low-Rank Adaptation of Large Language Models (arxiv.org)&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;div class=&#34;post-img-view&#34;&gt;
  &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230706171541.png&#34;&gt;
    &lt;img alt=&#34;image.png&#34; loading=&#34;lazy&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230706171541.png&#34;class=&#34;responsive-image&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230706171541.png&#34; style=&#34;display: block; margin: 0 auto;&#34;
      alt=&#34;image.png&#34;  /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;script&gt;
  document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
      var images = document.querySelectorAll(&#34;.responsive-image&#34;);
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + &#34;px&#34;;
      });
  });
&lt;/script&gt;
&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p>该章节主要介绍 Stable-Diffusion 中模型的训练，考虑到硬件条件的限制，实际上这里介绍的训练，都是针对大模型的各种微调技术（Lora，Dreambooth，HyperNetwork, &hellip;），这里会以 LoRA 模型的训练为主。</p>
</blockquote>
<p>参考文献：</p>
<ul>
<li><a href="http://www.gamelook.com.cn/2023/04/514936" target="_blank" rel="noopener">AIGC教程：Stable Diffusion精进，如何训练特定画风LoRA模型？ | 游戏大观 | GameLook.com.cn</a>
</li>
<li><a href="https://www.cnblogs.com/wangiqngpei557/p/17301360.html" target="_blank" rel="noopener">stable diffusion打造自己专属的LORA模型 - 王清培 - 博客园 (cnblogs.com)</a>
</li>
<li><a href="https://github.com/kohya-ss/sd-scripts/blob/main/train_README-zh.md" target="_blank" rel="noopener">sd-scripts/train_README-zh.md at main · kohya-ss/sd-scripts · GitHub</a>
</li>
</ul>
<h2 id="train-lora">Train LoRA</h2>
<blockquote>
<p>LoRA 的优势就是其模型更小，且更加模块化；也就是说其的训练成本和要求都更低，同时使用代价小，可以作为某种风格插件或者角色插件来使用。</p>
</blockquote>
<ul>
<li><a href="https://huggingface.co/blog/zh/lora" target="_blank" rel="noopener">使用 LoRA 进行 Stable Diffusion 的高效参数微调 (huggingface.co)</a>
</li>
<li><a href="https://arxiv.org/abs/2106.09685" target="_blank" rel="noopener">[2106.09685] LoRA: Low-Rank Adaptation of Large Language Models (arxiv.org)</a>
</li>
</ul>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230706171541.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230706171541.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230706171541.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>其中蓝色的是预训练好的源网络，而橙色的是新加的网络，通过控制 R 的宽度（文章主要论证了大模型的参数可能存在较低维度的秩，因此可以使用较小的 R 来对大模型的参数造成有效的影响），可以有效的减少需要训练的网络的 Size。</p>
<h3 id="事前准备">事前准备</h3>
<blockquote>
<p>这里只介绍本地训练，训练也可以在 Colab Notebook 等在线训练集群中进行，这里就不进行介绍了</p>
</blockquote>
<ol>
<li>WebUI + 想训练的基础 SD 模型</li>
<li><code>.txt</code> 带说明的文本文件</li>
<li>Training Repo（<a href="https://github.com/kohya-ss/sd-scripts" target="_blank" rel="noopener">sd-script</a>
、<a href="https://github.com/Akegarasu/lora-scripts" target="_blank" rel="noopener">lora-script</a>
）</li>
<li>数据集准备（准备好训练图像）</li>
</ol>
<h3 id="训练包准备">训练包准备</h3>
<p>这里我们使用 lora-script 来进行模型训练，lora-script 实际上是 sd-script 之外在包了一层，新增了一些可视化的功能和一些其他的脚本，让 sd-script 更加易用，它调用 sd 中的脚本来实现训练，但是封装了一些注释和整理，此外还支持的 tensorboard 可视化。</p>
<blockquote>
<p>sd-script 本身包含了训练 lora、dreambooth、text-embedding、UNet、Text Encoder、图像生成、模型转换等多种功能。lora-script 还是主要专注于 LoRA 训练</p>
</blockquote>
<p>查看 repo 也能知道 lora-script 中包含了 sd-script，所以我们部署的时候只需</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git clone --recurse-submodules https://github.com/Akegarasu/lora-scripts</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>即可将需要的库安装下来，然后安装环境和相关以来只需要执行 <code>.\install.ps1</code> 即可（该脚本有 cn 版本，但是可能会出现问题），其会安装 sd-scripts 和 lora-scripts 需要的库。具体的可以参考相关 repo（sd-script 详细说明，lora-script 有简化版说明）。</p>
<blockquote>
<p>安装的时候可能会出现虚拟环境未激活的问题，我们可以提前在改目录执行一次 python -m venv venv 一次即可。</p>
</blockquote>
<p>Finish.</p>
<h3 id="数据集准备">数据集准备</h3>
<blockquote>
<p>准备数据集的时候，要根据当前的设备显存对图片进行预处理，避免图片的分辨率过大，导致显存爆了，这里可以使用微软自己的 Powertoys 对文件进行批量 resize。</p>
</blockquote>
<p><strong>数据需求：</strong></p>
<ul>
<li>如果希望有<strong>更好的泛化性</strong>，训练素材中应该包含各种：角度、表情、光线。
<ul>
<li>如果是角色的话，建议尽可能的手机正面，侧面，背面，头像特写，</li>
<li>画风素材可以多一点</li>
<li>可以考虑扣白底： <a href="https://pickwant.com/home" target="_blank" rel="noopener">https://pickwant.com/home</a>
</li>
</ul>
</li>
<li>简单预处理：调整分辨率（64 的倍数），裁剪。</li>
<li>数据量：如果是角色训练集在 20~50 左右足够，但是重要的是训练数据和训练轮次之间需要根据可视化做一个协调，避免过拟合（有时候可能也允许过拟合，取决于使用的场景）或者欠拟合的情况发生，原则上讲数据数量和轮次是正相关的关系。</li>
</ul>
<p>预处理之<strong>生成图像描述</strong>：图像描述实际上是作为训练的标签存在，而显然，我们需要自动生成描述，如果还记得之前的文档，图生图功能中有<strong>反向推演提示词</strong>的方法，同样我们也会用该 Deepbooru 方法去生成标签，webui 中提供了一个专门的入口：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230507164237.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230507164237.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230507164237.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>在 resize 完成后，我们执行改生成图像描述的方法，指定好原图像位置和预处理之后的文件夹名字位置即可。</p>
<ul>
<li>预处理之后的文件夹会包含原图和对应生成的描述 txt 文件。</li>
<li>生成的描述文件可以 check 一下进行手动修改，错误的标签可能会引导出错误的训练方向。</li>
<li>为了便于 LoRA 的后续描述生成相同的效果，可以删除部分不必要的标签，令重要的标签和效果的相关度提高，并覆盖部分细节标签，可以理解成把一系列标签打包成一个标签。</li>
</ul>
<p><strong>训练数据就位：</strong> 将训练数据转移到 <code>&lt;...&gt;/lora-scripts/train/</code> 中，如果没有该 train 目录就创建一个，单次的训练数据放在一个文件夹中，例如 <code>&lt;..&gt;/train/train_1_person/</code></p>
<p><strong>正则化数据准备</strong>(option)：在 train 中新建一个 reg 文件夹，用于正则化训练，命名和此次训练的文件夹名相同，例如：<code>&lt;..&gt;/train/reg/train_1_person/</code>，在其中放的数据和训练数据应该是同类的不同对象。</p>
<blockquote>
<p>正则化的作用通常是避免模型过拟合，对模型添加额外的约束。例如我们训练一个猫，正则文件夹里应该同样存放猫（别的猫）的照片。</p>
</blockquote>
<p><strong>基础模型就位</strong>：将训练用到的基础模型复制到 <code>&lt;...&gt;/lora-scripts/sd-models/</code> 中，lora 是针对基础模型的注入（额外的 FC），对原模型进行部分的调整。</p>
<p><strong>注意事项：</strong> 避免文件名重复，使用相同的文件后缀能够避免文件名重复的问题。</p>
<h3 id="训练脚本编辑">训练脚本编辑</h3>
<p>better read: <a href="https://github.com/kohya-ss/sd-scripts/blob/main/train_network_README-zh.md" target="_blank" rel="noopener">sd-scripts/train_network_README-zh.md at main · kohya-ss/sd-scripts (github.com)</a>
</p>
<p>接下来就是编辑训练脚本中的基础设置，lora-scripts 中的注释已经非常详细的写好了每个参数的含义，这里就介绍一些可能需要或者常用的参数设置：</p>
<p>训练相关的一些设置如下</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230507170822.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230507170822.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230507170822.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ul>
<li><code>save_every_n_epochs </code> 会决定我们最终获得几个模型，这里也可以设置一下。</li>
<li><code>reg_data_dir</code> 设置正则化的目录，为空为默认不启用。</li>
<li>&hellip; 其他的看看注释</li>
</ul>
<p>还有一些输出相关的设置，包括输出模型的目录和名称，名称最好修改，避免一直都是默认的错误覆盖了：</p>
<blockquote>
<p>目录最好用 10_&lt;EN&gt; 或者纯数字的目录，然后路径填写的时候只填写到上级目录，比如说数据存放在 <code>&lt;...&gt;/train/10_ron</code>，那么脚本中就填写到 <code>./train</code>，正则化目录同理。</p>
</blockquote>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230507171041.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230507171041.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230507171041.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>其他参数设置简单推荐：</p>
<ul>
<li>unet_lr 一般=lr</li>
<li>lr_scheduler: <code>constant_with_warmup</code> 用的蛮多</li>
<li>优化器：
<ul>
<li>use_lion 目前最好的，但是有正则化素材最好别开</li>
</ul>
</li>
</ul>
<p>编辑完成后直接执行该 <code>ps1</code> 脚本即可。</p>
<blockquote>
<p>脚本运行过程中可能会出现 nomodule named triton 的错误，可能是由于 windows 不支持该模块导致的，但是不影响最后的生成。</p>
</blockquote>
<h3 id="lora-模型测试和选择">LoRA 模型测试和选择</h3>
<p>将模型导入 <code>/extensions/sd-webui-additional-networks/models/lora</code> 中，然后利用之前介绍过的 scripts 的 xyzplot 功能，分别测试和对比各个模型的效果，选择其中效果好的保留。</p>
<h3 id="成品展示--简单心得">成品展示 &amp; 简单心得</h3>
<blockquote>
<p>用我家猫小荣的 10-14 张照片训练出来了小荣的 Lora 模型（DreamBooth）也训了一下，但是显存（3070）不太够。</p>
</blockquote>
<p>训练 Lora 中使用了如下的参数配置：</p>
<ul>
<li>Clilloutmix 作为底层模型</li>
<li>使用训练 DreamBooth 中生成的 700 张猫的图片作为正则化数据集</li>
<li>BatchSize=2，Lr=e-4, Lion, Cosine_with_restarts, Max_train_epoch=10</li>
</ul>
<p>此外，由于图片少（一致性太强）训练轮次多，应该是有些过拟合，Lora 调用时只能在 3 以下，不然难以和原图区分，可以对训练轮次和图片数量做一下调整。</p>
<p>训练的时候打标签除了自动生成的，最好还是主动去修改，各种细节剖开来，描述好姿势，颜色，背景，表情等，后面学到的模型对各个部分进行修改的化比较方便区分，避免全都耦合在一起。</p>
<p>此外标签中要给特定的对象一个特定的标签，方便我们产出该指定效果（或者角色）。</p>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
    <script src="https://cdn.jsdmirror.com/npm/jquery@3.3.1/dist/jquery.min.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdmirror.com/npm/nanogallery2@3.0.5/dist/css/nanogallery2.min.css">
    <script src="https://cdn.jsdmirror.com/npm/nanogallery2@3.0.5/dist/jquery.nanogallery2.min.js"></script>
</head>
<body>

<div data-nanogallery2='{
	 "thumbnailDisplayTransition":          "none",
     "thumbnailDisplayTransitionDuration":  500,
     "thumbnailDisplayInterval":            30,
     "galleryDisplayTransition":            "none",
     "galleryDisplayTransitionDuration":    500,
     "galleryDisplayMode": "rows",
     "thumbnailDisplayOutsideScreen": "false",
     "eventsDebounceDelay": 10,
     "thumbnailL1BorderHorizontal": 0,
     "thumbnailL1BorderVertical": 0,
     "thumbnailLabel": {
        "titleFontSize": "0.6em"
     },
     "thumbnailHoverEffect2": "image_scale_1.00_1.10|label_backgroundColor_rgba(0,0,0,0)_rgba(255,255,255,0)",
     "galleryTheme": {
        "thumbnail": {
            "borderRadius": "8px"
        }
     },
     "thumbnailToolbarImage": {
        "topLeft": "",
        "topRight": "",
        "bottomLeft": "",
        "bottomRight": ""
     },
     "viewerToolbar":   {
        "display": true,
        "standard": "label"
     },
     "viewerTools":     {
        "topLeft":    "pageCounter, playPauseButton",
        "topRight":   "downloadButton, rotateLeft, zoomButton, fullscreenButton, closeButton"
     },
     "viewerGalleryTWidth": 40,
     "viewerGalleryTHeight": 40
}'>
     
<a href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00009-3706840146.png" data-ngThumb="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00009-3706840146.png">00009-3706840146.png</a>
<a href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00021-1903439770.png" data-ngThumb="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00021-1903439770.png">00021-1903439770.png</a>
<a href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00031-4141742147.png" data-ngThumb="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00031-4141742147.png">00031-4141742147.png</a>
<a href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00034-1003575578.png" data-ngThumb="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00034-1003575578.png">00034-1003575578.png</a>
<a href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00000-4244496505.png" data-ngThumb="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00000-4244496505.png">00000-4244496505.png</a>
<a href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00021-3282103832.png" data-ngThumb="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00021-3282103832.png">00021-3282103832.png</a>
<a href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00024-4215830362.png" data-ngThumb="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00024-4215830362.png">00024-4215830362.png</a>
<a href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00056-533810957.png" data-ngThumb="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00056-533810957.png">00056-533810957.png</a>
<a href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00001-2335627500.png" data-ngThumb="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00001-2335627500.png">00001-2335627500.png</a>

</div>
</body>
</html>
<h2 id="dreambooth">Dreambooth</h2>
<blockquote>
<p>DreamBooth: Fine Tuning Text-to-Image Diffusion Models for Subject-Driven Generation。
这种训练方式旨在微调 diffusion model 使其生成的图像专注于某个 object，具体可以看下面的示例图</p>
</blockquote>
<p>相关资源链接： <a href="https://github.com/d8ahazard/sd_dreambooth_extension" target="_blank" rel="noopener">webui训练插件</a>
 | <a href="https://github.com/google/dreambooth" target="_blank" rel="noopener">offical repo</a>
 | <a href="https://arxiv.org/abs/2208.12242" target="_blank" rel="noopener">Paper</a>
 | <a href="https://juejin.cn/post/7219968440760582205" target="_blank" rel="noopener">Dreambooth原理与实践</a>
</p>
<blockquote>
<p>如果需要深入了解实现原理的可以查看官方论文和对应的 repo 内容。</p>
</blockquote>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230511172006.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230511172006.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230511172006.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>其具备以下的优势：</p>
<ul>
<li>仅需要同一个<strong>主体（动物，模型，等）</strong> 的少量图片即可（3 到 5 张可以，但是越多越好）</li>
<li>可以基于该主体生成各种图片</li>
</ul>
<blockquote>
<p>针对该场景考虑将训练数据扣成白底可能也会使得生成的效果更好。</p>
</blockquote>
<p>具体的训练的详细介绍，可以参考训练插件页面的说明进行尝试，这里简单介绍一下工作流程：</p>
<p><strong>A. 模型创建</strong>：Dreambooth tab -&gt; &ldquo;Create Model&rdquo; sub-tab -&gt; 确定一个新的模型名称 -&gt;选择本地的模型 / HF(model URL &amp; token) -&gt; 确定后源 ckpt 会暂时存储在 <code>models\dreambooth\MODELNAME\working</code> -&gt; 点击 Create</p>
<p><strong>B. 参数设置</strong>：Settings tab -&gt; 是否使用 LoRA、BatchSize、Epochs 、学习率等等的设置都是基本的参数就不在介绍</p>
<blockquote>
<p>设置(settings)中的 <code>performance wizard (WIP)</code> 中可以查看建议的参数。</p>
</blockquote>
<p><strong>C. Concepts 设置</strong>：主要有两个类别：数据路径 + （class + prompt）</p>
<ul>
<li>数据路径不在赘述</li>
<li>Prompt 指的是我们的目标样本应该用什么提示词</li>
<li>Class 填入的是与目标同类但是不同个体的样本，避免过拟合</li>
</ul>
<p><strong>D. Saving 设置</strong>： 主要是设置我们各种模型的保存策略，类似步长之类的。</p>
<p><strong>E. Generate 设置</strong>：生成过程中的调整</p>
<p>设置完成后开始训练即可，可以看训练中的 loss 和模型训练过程中生成的图片，AFK，训练完成后就可以看到训练好的 CKPT 了。</p>
<h2 id="textual-inversion">Textual Inversion</h2>
<p>相关资源链接：<a href="https://arxiv.org/abs/2208.01618" target="_blank" rel="noopener">论文</a>
 | <a href="https://github.com/rinongal/textual_inversion" target="_blank" rel="noopener">官方代码</a>
 | <a href="https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Textual-Inversion" target="_blank" rel="noopener">webui说明</a>
 | <a href="https://textual-inversion.github.io/" target="_blank" rel="noopener">textual-inversion.github.io</a>
</p>
<blockquote>
<p>其全称为 An Image is Worth One Word: Personalizing Text-to-Image Generation using Textual Inversion</p>
</blockquote>
<p><strong>Textual Inversion</strong>： 功能和其名字相互对应，反转 Text2Img 的过程，Img2Text 地建立图像与指定文本（Prompt）的关联。也就是说，当我们希望输入特定的 Prompt 能稳定的产生某个效果的时候，可以利用 Textual Inversion 技术来对模型进行改造，使得该特定的 prompt 能取得特定效果。</p>
<p>实际上该技术也能取得和 Dreambooth 类似的效果，具体可以看论文和例子，这里也只简单介绍一下训练和使用。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230512085236.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230512085236.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230512085236.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><strong>A. 创建 Word Embedding</strong>（指定 Prompt）：</p>
<p>在 Train 标签页下创建 Embedding 页面，name 指定一个关键字（prompt），该 prompt 代表我们后续要训练出来的概念，创建完成后，就可以在 <code>/&lt;...&gt;/stable-diffusion-webui/embeddings</code> 路径下看到我们创建的 pt 文件</p>
<p><strong>B.数据预处理</strong>：同 Lora 介绍的预处理图像，准备好训练数据</p>
<p><strong>C.参数设置</strong>：</p>
<ul>
<li>Train-&gt; Train 页面中，只训练 Embedding，所以 Hypernetwork 的地方放空。</li>
<li>填写的基本学习率等参数就不再赘述，</li>
<li><strong>填写</strong>：数据集目录、Log 目录等即可</li>
<li>&ldquo;Prompt template&quot;需要注意下, 提供了几种可选的训练模式:
<ul>
<li>style_filewords.txt: 表示训练画风</li>
<li>subject_filewords.txt: 表示训练人物或物体</li>
</ul>
</li>
</ul>
<p><strong>D.选择训练 Embedding</strong>：即可开始训练</p>
<p><strong>E.使用</strong>：放在 <code>/&lt;...&gt;/stable-diffusion-webui/embeddings</code> 中，在相关生成过程中，填写 Prompt 的时候像 easynagetive 启用即可。</p>
<h2 id="hypernetworks">HyperNetworks</h2>
<p><a href="https://blog.novelai.net/novelai-improvements-on-stable-diffusion-e10d38db82ac" target="_blank" rel="noopener">NovelAI Improvements on Stable Diffusion | by NovelAI | Medium</a>
</p>
<blockquote>
<p>Hypernetwork 是一种微调技术（by Novel AI ），它是一个<strong>小型附加神经网络</strong>附加在 Stable Diffusion 模型上以修改其风格，这种方式和当时的论文并不一致，当时的 HyperNetwork 是通过修改权重来进行调整，NovelAI 中使用到的则是添加一个小型的线性附加网络。</p>
</blockquote>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230706170343.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230706170343.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230706170343.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>具体而言，其插入到噪声预测器 UNet 的交叉注意力模块中，（通常情况下是一个简单的神经网络：具有 dropout 和激活函数的全连接线性网络）通过插入两个转换 key 和 query 向量的网络来劫持交叉注意力模块。</p>
<p>其训练过程与 Text Inversion 几乎一致，这里就不在赘述，只描述部分不同：</p>
<ul>
<li>创建模型的时候在 Train/Create Hypernetwork 选项卡</li>
<li>训练的时候选择 train hypernetwork</li>
<li>使用时存放的目录（应该也可以存放在 Addition Network 的文件夹中）为： <code>stable_difusion\stable-diffusion-webui\models\hypernetworks</code> 像 Lora 一样启用即可。</li>
</ul>
<h2 id="fi">FI</h2>
<p>stable diffusion 的介绍暂时就到这边了，原理相关的东西就先不介绍了，以后如果有必要的话，或者谁有需求的话可以联系我更新。</p>
<ul>
<li><input checked="" disabled="" type="checkbox"> 通过训练小荣来给出一个详细的参数设置（Dreambooth 和 Lora 和 TextInversion）</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>使用Immich备份家庭照片</title>
      <link>https://aikenh.cn/posts/immich_backup/</link>
      <pubDate>Mon, 01 May 2023 09:12:04 +0000</pubDate>
      <guid>https://aikenh.cn/posts/immich_backup/</guid>
      <description>using immich to backup all the photos of your home.</description>
      <content:encoded><![CDATA[<blockquote>
<p>手机到电脑端的图像备份和预览往往是一个大问题，特别是当多个手机要备份的时候，说难不难，但说简单也确实有很多麻烦的地方，因此我推荐 Immich 的解决方案。</p>
</blockquote>
<p>Immich 是一个基于个人开发者开发的开源 Github 项目，<a href="https://github.com/immich-app/immich" target="_blank" rel="noopener">immich-app/immich</a>
，该解决方案有以下的一些优势：</p>
<ul>
<li>移动端支持：移动端实现便于手机的随时和自动同步；</li>
<li>多用户支持：多用户的权限管理、分割、以及用户间的相册共享；</li>
<li>Live 格式支持：支持各种原生格式存储，</li>
</ul>
<blockquote>
<p>Self-hosted photo and video backup solution directly from your mobile phone.</p>
</blockquote>
<p>因此我本人推荐按照以下的方式来使用：针对家庭等环境，多用户部署在 NAS 或者某台 PC 上，可以长期或者定期的启动备份服务，然后就可以将手机中的照片空间释放掉。由此可以实现：</p>
<ol>
<li>通过共享文件夹共建家庭相册；</li>
<li>权限分割个人相册；</li>
<li>定期/自动备份手机中的照片，并清理对应的存储空间；</li>
</ol>
<h2 id="install-安装和部署">Install 安装和部署</h2>
<p>官方网站中有各种不同环境下安装的说明和实例已经足够详细，强烈建议根据自己的不同需求查看相关文档；和官方一样，我这边也推荐使用 <strong>docker compose</strong> 进行安装和部署。Thanks to docker，部署与安装变得简单。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mkdir ./immich_app
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> ./immich_app</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="download-下载">Download 下载</h3>
<p>安装实际上只需要两个文件，一个是 <code>.env</code> 用来填写配置，另一个是 <code>docker-compose.yml</code> 文件用来拉取镜像和部署。</p>
<p><strong>下载</strong> <code>docker-compose.Yml </code> 文件和 <code>example.env</code> 文件，可以使用下列的 wget 命令，或者直接去对应的 Page。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># get compose file.</span>
</span></span><span class="line"><span class="cl">wget https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><blockquote>
<p>接着下载 example env 文件，在完成了配置填写后记得将其重命名为 <code>.env</code></p>
</blockquote>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># get the exmple env file.</span>
</span></span><span class="line"><span class="cl">wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.env</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="configuration-配置">Configuration 配置</h3>
<p>env 的详细文件说明查看：<a href="https://immich.app/docs/install/docker-compose" target="_blank" rel="noopener">Docker Compose [Recommended] | Immich</a>
，主要需要修改或者填写的地方有：</p>
<ul>
<li><strong>UPLOAD_LOCATION</strong>：存储图像备份文件的地址。</li>
<li><strong>TYPESENSE_ENABLED</strong>: 如果出现一些问题报错的话，可能需要添加此项，并将其设置为 false</li>
<li><strong>其他的参考配置</strong>官方的即可。</li>
</ul>
<h3 id="start-启动服务">Start 启动服务</h3>
<p>使用 docker compose command 启动对应的 containers 即可。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker-compose up -d</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230502191953.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230502191953.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230502191953.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>最终呈现的效果大致如图，其他的功能，比如下面的用户管理，图像识别等自动任务，还有一些就不逐一展示了，移动端的使用也十分简单，只要指定好对应的用户密码，以及 ip 端口即可连接，（须在同一个局域网内，或者使用内网穿透）</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230502192530.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230502192530.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230502192530.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>该界面上可以在线预览，管理相册，查看存储情况，自动识别图像种类等等，手机端则主要是用于同步。</p>
<h3 id="upgrade-更新">Upgrade 更新</h3>
<p>进入到 docker-compose 对应的目录中，重新拉取镜像再重新启动即可。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker-compose pull <span class="o">&amp;&amp;</span> docker-compose up -d</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="troubleshooting">TroubleShooting</h2>
<p>A. 启用用户登录后还是显示禁止了用户登录；</p>
<blockquote>
<p>可以看看对应的登录界面可不可以下拉，下拉可以看到登录界面，应该是前端未刷新的问题。</p>
</blockquote>
<p>B. 局域网无法访问的时候检查防火墙通行。</p>
<blockquote>
<p>检查防火墙对 Docker Desktop 的放行</p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>Windows App01 Potplayer &amp; Alist</title>
      <link>https://aikenh.cn/posts/alist_potplayer/</link>
      <pubDate>Sun, 30 Apr 2023 22:42:58 +0000</pubDate>
      <guid>https://aikenh.cn/posts/alist_potplayer/</guid>
      <description>intro how we use potplayer with alist,</description>
      <content:encoded><![CDATA[<blockquote>
<p>本篇主要介绍一下播放器 PotPlayer 的设置以及结合 Alist&amp;小雅 alist 的使用，这样就可以直接在播放器访问本地网盘上的内容，便于使用和观看。</p>
</blockquote>
<h2 id="alist-deploy">Alist Deploy</h2>
<p>Alist 作为一个网盘管理中心，可以将各大网盘中的资源进行统一管理，同时支持视频的 webdav 播放，这里推荐的安装方式是使用 Docker-Compose 进行安装，根据自己的情况来选择对应的挂载和安装目录。</p>
<p>由于官方的文档已经事无巨细，这里就不在赘述如何安装和配置 alist 的各个网盘挂载，详情参见：<a href="https://alist.nn.ci/" target="_blank" rel="noopener">Home | AList Docs (nn.ci)</a>
</p>
<p>安装完并<strong>启动 Alist 服务</strong>即可，记住自己的<strong>端口</strong>和设置的<strong>账号密码</strong>。</p>
<h3 id="aria2离线下载支持">Aria2离线下载支持</h3>
<p>该部分介绍如何通过 docker 为 Alist 添加 Aria2 作为离线下载服务，以及一些常见的问题解决方法。</p>
<p>参考资料：<a href="https://p3terx.com/archives/docker-aria2-pro.html" target="_blank" rel="noopener">aria2-pro</a>
 |  <a href="https://github.com/P3TERX/Aria2-Pro-Docker/blob/master/docker-compose.yml" target="_blank" rel="noopener">aira2-pro-github</a>
 |  <a href="https://yiwangmeng.com/aria2-status-page-to-prompt-the-solution-of" target="_blank" rel="noopener">aria2认证失败</a>
</p>
<p>这里介绍使用 docker-compose 安装 aria2的方法，并将 docker 版本的 aria2和 alist 结合起来使用，在基于 docker 安装之前，我们先准备几个文件夹：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">cd</span> &lt;your-path-2-aria2&gt; <span class="o">&amp;&amp;</span> mkdir aria2-config <span class="o">&amp;&amp;</span> chmod <span class="m">777</span> aria2-config
</span></span><span class="line"><span class="cl">mkdir aria2-downloads <span class="o">&amp;&amp;</span> chmod <span class="m">777</span> aria2-downloads</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>其中 downloads 目录是我们用来下载文件的目录，我们也可以使用挂载的目录或者共享的目录来存储下载的文件；然后我们准备一下 alist 中用于离线下载的目录，<strong>该目录需要在 alist 的 docker 和 aria2的 docker 中都将该 volume 挂载到同一个地方</strong>。</p>
<p>本文将 aria2的队名目录挂载到 alist 的对应目录中，对应的 alist 的 compose 文件有</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230709161919.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230709161919.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230709161919.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>而 aria2的 compose 文件则有：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230709161956.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230709161956.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230709161956.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>再将该目录的权限改成777，<code>chmod 777 &lt;this-dir&gt;</code> 之后即可再 alist 中离线下载成功，而且该下载文件会在指定的网盘中上传，当上传完成时会删除临时文件，不占用本地磁盘空间。</p>
<p>完整的 Compose 文件可以参考 <a href="https://github.com/P3TERX/Aria2-Pro-Docker/blob/master/docker-compose.yml" target="_blank" rel="noopener">Aria2-Pro-Docker/docker-compose.yml at master · P3TERX/Aria2-Pro-Docker · GitHub</a>
 官方的配置进行安装，我个人的 compose 文件则会上传到<a href="https://github.com/AikenH/aikenh-DockerComposeYML" target="_blank" rel="noopener">AikenH/aikenh-DockerComposeYML (github.com)</a>
中。</p>
<p><strong>Aria2Ng 界面认证失败</strong>的问题，是因为我们再 compose 中设置了密码之后，要在该界面的设置中设置密码后才能正常认证。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230709162444.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230709162444.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230709162444.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>密码需要到如下地方设置：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230709162537.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230709162537.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230709162537.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>设置完成后应该就不会有认证失败的提示了。</p>
<p><strong>alist 设置 Aria2失败</strong>，由于使用的 docker 部署的 aria2，这里不能使用 localhost，要使用对应的 ip 来设置该服务，如下图所示</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230709162724.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230709162724.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230709162724.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>完成这些设置后应该就可以正常使用了，但是由于现在都是网盘场景更多，所以离线下载的可能使用场景也有限，而且通过测试发现，如果完全装在树莓派上的话，可能会对系统的性能造成一定的负担。</p>
<h2 id="xiaoya-deploy">Xiaoya Deploy</h2>
<blockquote>
<p>Xiaoya 是基于 Alist 做改版的个人资源站，里面涵盖了大量的影视资源，并在不断的更新，通过在本地挂载 xiaoya 我们也可以用来通过 webdav 在播放器中直接选择视频进行播放，大多数情况下都免去了找资源的痛苦。</p>
</blockquote>
<p>官方网站：<a href="http://alist.xiaoya.pro/" target="_blank" rel="noopener">主页 | 小雅的分类 Alist (xiaoya.pro)</a>
</p>
<p>拥有了 Docker 环境后，就可以基于 xiaoya 提供的脚本实现一键拉取镜像和启动 Docker，默认的端口是 5678，安装指令如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo bash -c <span class="s2">&#34;</span><span class="k">$(</span>curl -s http://docker.xiaoya.pro/update_new.sh<span class="k">)</span><span class="s2">&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>安装过程中会需要填入如下内容：token、open_token、转存目录的 folder id，具体和后续更新参考<a href="https://xiaoyaliu.notion.site/xiaoya-docker-69404af849504fa5bcf9f2dd5ecaa75f" target="_blank" rel="noopener">配置页</a>
，（跟随安装引导界面进行安装即可。）</p>
<table>
  <thead>
      <tr>
          <th></th>
          <th>对应文件</th>
          <th>获取方式</th>
          <th></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>token</td>
          <td>/etc/xiaoya/mytoken.Txt</td>
          <td><a href="https://aliyuntoken.vercel.app/" target="_blank" rel="noopener">link 1</a>
 <a href="https://alist.nn.ci/zh/guide/drivers/aliyundrive.html" target="_blank" rel="noopener">link 2</a>
</td>
          <td></td>
      </tr>
      <tr>
          <td>open token</td>
          <td>/etc/xiaoya/myopentoken.Txt</td>
          <td><a href="https://alist.nn.ci/zh/guide/drivers/aliyundrive_open.html" target="_blank" rel="noopener">https://alist.nn.ci/zh/guide/drivers/aliyundrive_open.html</a>
</td>
          <td></td>
      </tr>
      <tr>
          <td>转存目录的 folder id</td>
          <td>/etc/xiaoya/temp_transfer_folder_id.Txt</td>
          <td>在阿里网盘网页版上创建一个转存目录，比如“temp”，然后点击目录，浏览器显示的 URL <a href="https://www.aliyundrive.com/drive/folder/640xxxxxxxxxxxxxxca8a" target="_blank" rel="noopener">https://www.aliyundrive.com/drive/folder/640xxxxxxxxxxxxxxca8a</a>
 最后一串就是</td>
          <td></td>
      </tr>
  </tbody>
</table>
<p>安装完成后确保服务启动正常，该部分的准备即结束，但是该端口我们还是要记住，因为在大量资源中搜索的时候还是得<strong>借助网页版中的搜索功能</strong>。</p>
<p>安装完成后后续使用 Potplayer 挂载 Dav 时，账号密码为：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">guest
</span></span><span class="line"><span class="cl">guest_Api789</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="potplayer-设置">PotPlayer 设置</h2>
<blockquote>
<p>支持 WebDav 的免费视频播放器，同时也支持音乐播放，录频截图等功能，虽然支持 Iptv 源，但是实际上很多频道都比较卡，所以不是很推荐（也可能是我没找到好用的源，如果有的话感谢分享。）</p>
</blockquote>
<p>参考资料：<a href="https://zhuanlan.zhihu.com/p/163458215" target="_blank" rel="noopener">Potplayer全面设置教程</a>
，最后配置完的设置和对应的皮肤文件我会到处到我的 dotfile 仓库。</p>
<h3 id="基础设置">基础设置</h3>
<p>具体的设置和皮肤下载路径如下：</p>
<ul>
<li><strong>下载</strong>：<a href="https://www.deviantart.com/search?q=potplayer" target="_blank" rel="noopener">Search &lsquo;potplayer&rsquo; on DeviantArt</a>
</li>
<li><strong>基本</strong> -&gt; 皮肤/配色 -&gt; 打开皮肤文件夹 -&gt; 进阶皮肤 -&gt; 启用 Direct3D 渲染。</li>
<li><strong>播放</strong> -&gt; 打开多线程，旋转，标题，记忆位置，隐蔽指针，进度条显示缩略图，以及设置是否循环播放。
<ul>
<li>时间跨度 -&gt; 设置一下方向键快进的时间</li>
<li>列表 -&gt; 显示缩略图和两行信息，按文件路径排序并全部对齐</li>
<li>宽高比 -&gt; 缩放时保持宽高比</li>
</ul>
</li>
<li><strong>字幕</strong> -&gt; 画面底部、自动重载被修改的字幕
<ul>
<li>可以通过播放时右键 -&gt; 实时字幕翻译 -&gt; 使用</li>
<li>详细的设置在：选项 -&gt; 拓展功能 -&gt; 实时字母翻译</li>
</ul>
</li>
<li>滤镜相关的我这里不懂就不设置</li>
<li><strong>声音</strong> -&gt; 最大音量调整到 200</li>
</ul>
<p>效果展示如下：</p>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
    <script src="https://cdn.jsdmirror.com/npm/jquery@3.3.1/dist/jquery.min.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdmirror.com/npm/nanogallery2@3.0.5/dist/css/nanogallery2.min.css">
    <script src="https://cdn.jsdmirror.com/npm/nanogallery2@3.0.5/dist/jquery.nanogallery2.min.js"></script>
</head>
<body>

<div data-nanogallery2='{
	 "thumbnailDisplayTransition":          "none",
     "thumbnailDisplayTransitionDuration":  500,
     "thumbnailDisplayInterval":            30,
     "galleryDisplayTransition":            "none",
     "galleryDisplayTransitionDuration":    500,
     "galleryDisplayMode": "rows",
     "thumbnailDisplayOutsideScreen": "false",
     "eventsDebounceDelay": 10,
     "thumbnailL1BorderHorizontal": 0,
     "thumbnailL1BorderVertical": 0,
     "thumbnailLabel": {
        "titleFontSize": "0.6em"
     },
     "thumbnailHoverEffect2": "image_scale_1.00_1.10|label_backgroundColor_rgba(0,0,0,0)_rgba(255,255,255,0)",
     "galleryTheme": {
        "thumbnail": {
            "borderRadius": "8px"
        }
     },
     "thumbnailToolbarImage": {
        "topLeft": "",
        "topRight": "",
        "bottomLeft": "",
        "bottomRight": ""
     },
     "viewerToolbar":   {
        "display": true,
        "standard": "label"
     },
     "viewerTools":     {
        "topLeft":    "pageCounter, playPauseButton",
        "topRight":   "downloadButton, rotateLeft, zoomButton, fullscreenButton, closeButton"
     },
     "viewerGalleryTWidth": 40,
     "viewerGalleryTHeight": 40
}'>
     
<a href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230501003002.png" data-ngThumb="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230501003002.png"></a>
<a href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230501003054.png" data-ngThumb="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230501003054.png"></a>
<a href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230501003504.png" data-ngThumb="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230501003504.png"></a>

</div>
</body>
</html>
<h3 id="webdav-挂载-alist-和小雅">Webdav 挂载 Alist 和小雅</h3>
<p>播放列表中新建专辑，按照下图的方式进行填写，其中端口就是你 Alist 或者小雅在本地部署的端口，IP 如果是本地部署的话就按下列的方式填写，否则就填写提供的 IP，用户名和密码使用自己设置的用户密码即可（小雅的话可以参考默认账号和密码）</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230501003740.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230501003740.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230501003740.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>至此，PotPlayer 和对应的 Alist 列表就挂载成功了，可以畅爽实现本地看剧了。</p>
<h3 id="iptv-列表">Iptv 列表</h3>
<p>虽然不推荐使用 Iptv 因为大多数源是真的卡，看起来要么卡，要么不够高清，要么找一个频道找半天，确实是不是很想费心折腾这块，也不建议，但是还是简单介绍。</p>
<p>使用的话就将下载的 iptv 源文件拖入播放列表即可，下面有几个 iptv 源的地址：</p>
<ul>
<li><a href="https://github.com/iptv-org/iptv" target="_blank" rel="noopener">iptv-org/iptv: Collection of publicly available IPTV channels from all over the world (github.com)</a>
</li>
<li><a href="https://github.com/imDazui/Tvlist-awesome-m3u-m3u8" target="_blank" rel="noopener">imDazui/Tvlist-awesome-m3u-m3u8: 直播源相关资源汇总</a>
</li>
<li><a href="https://blog.xn--9kq250g.fun/index.php/iptv%E7%9B%B4%E6%92%AD%E6%BA%90/%E6%AF%8F%E5%A4%A9%E6%9B%B4%E6%96%B0%EF%BC%9A%E4%B8%AD%E5%9B%BD%E7%94%B5%E8%A7%86iptv%E7%9B%B4%E6%92%AD%E6%BA%90-m3u-1080p%E5%85%8D%E8%B4%B9%E9%AB%98%E6%B8%85%E7%89%88-2023%E5%B9%B41%E6%9C%881/" target="_blank" rel="noopener">每天更新：中国电视IPTV直播源.m3u</a>
</li>
<li><a href="https://github.com/fanmingming/live" target="_blank" rel="noopener">fanmingming/live: ✯ 一个国内可直连的直播源分享项目 ✯ 🔕 永久免费 直连访问 完整开源 不含广告 完善的台标 直播源支持IPv4/IPv6双栈访问 🔕 (github.com)</a>
</li>
<li><a href="https://www.foodieguide.com/iptvsearch/" target="_blank" rel="noopener">电视直播源搜索｜最新东森多线路直播源分享 (foodieguide.com)</a>
</li>
</ul>
<p>使用前可以使用 iptv-checker 来检查源的可用性，然后过滤掉一些不可用的源。</p>
]]></content:encoded>
    </item>
    <item>
      <title>AIGC04 Stable Diffusion Write Prompt Better</title>
      <link>https://aikenh.cn/posts/stablediffusionprompt/</link>
      <pubDate>Wed, 26 Apr 2023 21:22:38 +0000</pubDate>
      <guid>https://aikenh.cn/posts/stablediffusionprompt/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;该章节主要包括 Promot 生成和部分工作流的分析，旨在了解如何写出更好的关键词，如何生成更好的图片，当我们不知道怎么描述的时候也可以将该工作交给 ChatGPT，让其为我们攥写一般基础的提示词&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;prompt-编写范式&#34;&gt;Prompt 编写范式&lt;/h2&gt;
&lt;p&gt;参考资料：&lt;a href=&#34;https://zhuanlan.zhihu.com/p/619247417?utm_id=0&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;【Stable Diffusion】Prompt&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;通常编写可以遵照以下的类别进行组织，主要有 &lt;code&gt;&amp;lt;质量控制&amp;gt; + &amp;lt;前置&amp;gt; + &amp;lt;主体&amp;gt; + &amp;lt;场景词&amp;gt;&lt;/code&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;：人物&amp;amp;对象、姿势、服装、道具&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;场景&lt;/strong&gt;：环境、背景、细节&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Additional Network&lt;/strong&gt;：载入额外模型&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;分割符号：&lt;/strong&gt; 各个关键词之间用 &lt;code&gt;,&lt;/code&gt; 分割，且对应的权重从前到后依次递减，因此在编写关键词的时候也要注意先后顺序。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;权重加权符号&lt;/strong&gt;：各种括号代表各种不同的加权系数，这里建议用 &lt;code&gt;(prompt: weight)&lt;/code&gt; 统一来编写提示词的权重规则，整体可读性会更好。&lt;/p&gt;
&lt;p&gt;这里的 weight 指的是权重变成原本的 weight 倍，就可以调整加强或减弱。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;各个括号的默认系数如下: () -&amp;gt; 1.1 ; {} -&amp;gt; 1.05 ; &lt;code&gt;[]&lt;/code&gt; -&amp;gt; 0.952
可以通过(())进行叠加即 1.1*1.1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;额外模型调取&lt;/strong&gt;：编写格式为 &lt;code&gt;&amp;lt;lora:loramodelname:multiplier&amp;gt;&lt;/code&gt;，即载入 loramodelname 模型，权重为 multiplier，该权重不建议过大。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关键词的切换&lt;/strong&gt;： 语法如下 &lt;code&gt;[key1:key2:step]&lt;/code&gt;，通过该语法可以实现在进行到不同步骤的时候使用不同的关键词进行渲染，其中 &lt;code&gt;:key2&lt;/code&gt; 可以忽略，忽略后即可理解为 &lt;code&gt;[&amp;quot;&amp;quot;:key1:step]&lt;/code&gt;，有一下的一些规则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Step 在大于 1 时表示具体的步骤，小于 1 时表示迭代步数的百分比&lt;/li&gt;
&lt;li&gt;如果想要在某步之后忽略 key1，与上面忽略 key2 正好相反，可以写成 &lt;code&gt;[key1::step]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[key1|key2]&lt;/code&gt; 则表示两个关键词交替选择渲染&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;反向提示词&lt;/strong&gt;：反向提示词就是让 AI 避免生成什么样的图片，使用得当可以帮助我们更好的生成想要的图片，后面再关键词的地方会介绍一些常见的反向关键词，例如低画质相关和一些容易变形身体部位的描述等&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p>该章节主要包括 Promot 生成和部分工作流的分析，旨在了解如何写出更好的关键词，如何生成更好的图片，当我们不知道怎么描述的时候也可以将该工作交给 ChatGPT，让其为我们攥写一般基础的提示词</p>
</blockquote>
<h2 id="prompt-编写范式">Prompt 编写范式</h2>
<p>参考资料：<a href="https://zhuanlan.zhihu.com/p/619247417?utm_id=0" target="_blank" rel="noopener">【Stable Diffusion】Prompt</a>
</p>
<p>通常编写可以遵照以下的类别进行组织，主要有 <code>&lt;质量控制&gt; + &lt;前置&gt; + &lt;主体&gt; + &lt;场景词&gt;</code> 几类，其中分别包括以下的几类词：</p>
<ul>
<li><strong>质量控制</strong>：画质、镜头效果、光照效果</li>
<li><strong>前置词</strong>：画风、艺术家、风格</li>
<li><strong>主体</strong>：人物&amp;对象、姿势、服装、道具</li>
<li><strong>场景</strong>：环境、背景、细节</li>
<li><strong>Additional Network</strong>：载入额外模型</li>
</ul>
<p><strong>分割符号：</strong> 各个关键词之间用 <code>,</code> 分割，且对应的权重从前到后依次递减，因此在编写关键词的时候也要注意先后顺序。</p>
<p><strong>权重加权符号</strong>：各种括号代表各种不同的加权系数，这里建议用 <code>(prompt: weight)</code> 统一来编写提示词的权重规则，整体可读性会更好。</p>
<p>这里的 weight 指的是权重变成原本的 weight 倍，就可以调整加强或减弱。</p>
<blockquote>
<p>各个括号的默认系数如下: () -&gt; 1.1 ; {} -&gt; 1.05 ; <code>[]</code> -&gt; 0.952
可以通过(())进行叠加即 1.1*1.1</p>
</blockquote>
<p><strong>额外模型调取</strong>：编写格式为 <code>&lt;lora:loramodelname:multiplier&gt;</code>，即载入 loramodelname 模型，权重为 multiplier，该权重不建议过大。</p>
<p><strong>关键词的切换</strong>： 语法如下 <code>[key1:key2:step]</code>，通过该语法可以实现在进行到不同步骤的时候使用不同的关键词进行渲染，其中 <code>:key2</code> 可以忽略，忽略后即可理解为 <code>[&quot;&quot;:key1:step]</code>，有一下的一些规则：</p>
<ul>
<li>Step 在大于 1 时表示具体的步骤，小于 1 时表示迭代步数的百分比</li>
<li>如果想要在某步之后忽略 key1，与上面忽略 key2 正好相反，可以写成 <code>[key1::step]</code></li>
<li><code>[key1|key2]</code> 则表示两个关键词交替选择渲染</li>
</ul>
<p><strong>反向提示词</strong>：反向提示词就是让 AI 避免生成什么样的图片，使用得当可以帮助我们更好的生成想要的图片，后面再关键词的地方会介绍一些常见的反向关键词，例如低画质相关和一些容易变形身体部位的描述等</p>
<p>这里介绍一个 <code>easynegative</code> 的 embedding 模型，其是通过大量的不好的图片训练出来的模型，通过在反向关键词部分调用 easynegative 调用该模型即可过滤。</p>
<p>具体的使用方式如下：</p>
<p>首先去 C 站下载模型， <a href="https://civitai.com/models/7808/easynegative" target="_blank" rel="noopener">EasyNegative - EasyNegative | Stable Diffusion Textual Inversion | Civitai</a>
; 然后将其放入 <code>stable-diffuison-webui</code> 资料夹下的 <code>embeddings</code> 文件夹；重启之后在负向关键词中填入 EasyNegative 即可生效（也可从额外网络中选择 Textual inversion/tembeding，然后将该模型填入 Negative 中）</p>
<blockquote>
<p>但是单独使用的话，效果可能还是没有那么好，所以最好还是结合着一些特定的负向关键词一起使用。</p>
</blockquote>
<h2 id="keyword-关键词">Keyword 关键词</h2>
<p>该部分主要来自参考资料，<a href="https://zhuanlan.zhihu.com/p/619247417?utm_id=0" target="_blank" rel="noopener">原文推荐</a>
 阅读，如果觉得有用，请给原文点赞。</p>
<blockquote>
<p>通过在文章前面添加画质关键词能提升生成图片的质感，质量，描述简单通用而有效</p>
</blockquote>
<table>
  <thead>
      <tr>
          <th>prompt</th>
          <th>Desc</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>HDR, UHD, 8 k</td>
          <td>这样的质量词可以带来巨大的差异提升照片的质量</td>
      </tr>
      <tr>
          <td>Best quality</td>
          <td>最佳质量</td>
      </tr>
      <tr>
          <td>masterpiece</td>
          <td>杰作</td>
      </tr>
      <tr>
          <td>Highly detailed</td>
          <td>细节添加</td>
      </tr>
      <tr>
          <td>Studio lighting</td>
          <td>演播室灯光</td>
      </tr>
      <tr>
          <td>ultra-fine painting</td>
          <td>精细绘图</td>
      </tr>
      <tr>
          <td>sharp focus</td>
          <td>清晰聚焦</td>
      </tr>
      <tr>
          <td>physically-based rendering</td>
          <td>基于物理渲染</td>
      </tr>
      <tr>
          <td>extreme detail description</td>
          <td>详细刻画</td>
      </tr>
      <tr>
          <td>Professional</td>
          <td>改善图片的对比细节</td>
      </tr>
      <tr>
          <td>Vivid Colors</td>
          <td>色彩鲜艳</td>
      </tr>
      <tr>
          <td>Bokeh</td>
          <td>模糊背景，突出主题</td>
      </tr>
      <tr>
          <td>(EOS R8, 50mm, F1.2, 8K, RAW photo:1.2)</td>
          <td>相机设置</td>
      </tr>
      <tr>
          <td>High resolution scan</td>
          <td>年代感</td>
      </tr>
      <tr>
          <td>Sketch</td>
          <td>素描</td>
      </tr>
      <tr>
          <td>Painting</td>
          <td>绘画</td>
      </tr>
  </tbody>
</table>
<p>还有一些诸如：depth of field 景深、wide angle 广角之类术语，也能帮助我们生成更好的或者更符合预期的图片。</p>
<blockquote>
<p>可以通过添加艺术家关键词来使得生成图片具备特定风格，常用于固定的风格模仿。</p>
</blockquote>
<table>
  <thead>
      <tr>
          <th>prompt</th>
          <th>Artist</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>肖像画（Portraits）</td>
          <td>Derek Gores, Miles Aldridge, Jean Baptiste-Carpeaux, Anne-Louis Girodet</td>
      </tr>
      <tr>
          <td>风景画（Landscape）</td>
          <td>Alejandro Bursido, Jacques-Laurent Agasse, Andreas Achenbach, Cuno Amiet</td>
      </tr>
      <tr>
          <td>恐怖画（Horror）</td>
          <td>H.R.Giger, Tim Burton, Andy Fairhurst, Zdzislaw Beksinski</td>
      </tr>
      <tr>
          <td>动漫画（Anime）</td>
          <td>Makoto Shinkai, Katsuhiro Otomo, Masashi Kishimoto, Kentaro Miura</td>
      </tr>
      <tr>
          <td>科幻画（Sci-fi）</td>
          <td>Chesley Bonestell, Karel Thole, Jim Burns, Enki Bilal</td>
      </tr>
      <tr>
          <td>摄影（Photography）</td>
          <td>Ansel Adams, Ray Earnes, Peter Kemp, Ruth Bernhard</td>
      </tr>
      <tr>
          <td>概念艺术家（视频游戏）Concept artists video game</td>
          <td>Emerson Tung, Shaddy Safadi, Kentaro Miura</td>
      </tr>
  </tbody>
</table>
<blockquote>
<p>常用的反向 Prompt 常有如下的这些，实际上可以根据生成的情况放上去，或者根据需要的图片直接一股脑的放上去即可，希望 AI 画好一个元素，可以通过正 tag 结合反向的约束来实现。</p>
</blockquote>
<table>
  <thead>
      <tr>
          <th>negative prompt</th>
          <th>Desc</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>mutated hands and fingers</td>
          <td>变异的手和手指</td>
      </tr>
      <tr>
          <td>deformed</td>
          <td>变形的</td>
      </tr>
      <tr>
          <td>bad anatomy</td>
          <td>解剖不良</td>
      </tr>
      <tr>
          <td>disfigured</td>
          <td>毁容</td>
      </tr>
      <tr>
          <td>poorly drawn face</td>
          <td>脸画的不好</td>
      </tr>
      <tr>
          <td>mutated</td>
          <td>变异的</td>
      </tr>
      <tr>
          <td>extra limb</td>
          <td>多余的肢体</td>
      </tr>
      <tr>
          <td>ugly</td>
          <td>丑陋</td>
      </tr>
      <tr>
          <td>poorly drawn hands</td>
          <td>手画的不好</td>
      </tr>
      <tr>
          <td>missing limb</td>
          <td>缺少肢体</td>
      </tr>
      <tr>
          <td>floating limb</td>
          <td>漂浮的四肢</td>
      </tr>
      <tr>
          <td>disconnected limbs</td>
          <td>肢体不连贯</td>
      </tr>
      <tr>
          <td>malformed hands</td>
          <td>畸形的手</td>
      </tr>
      <tr>
          <td>out of focus</td>
          <td>脱离焦点</td>
      </tr>
      <tr>
          <td>long neck</td>
          <td>长脖子</td>
      </tr>
      <tr>
          <td>long body</td>
          <td>长身体</td>
      </tr>
  </tbody>
</table>
<h2 id="sample一些简单成品">Sample一些简单成品</h2>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
    <script src="https://cdn.jsdmirror.com/npm/jquery@3.3.1/dist/jquery.min.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdmirror.com/npm/nanogallery2@3.0.5/dist/css/nanogallery2.min.css">
    <script src="https://cdn.jsdmirror.com/npm/nanogallery2@3.0.5/dist/jquery.nanogallery2.min.js"></script>
</head>
<body>

<div data-nanogallery2='{
	 "thumbnailDisplayTransition":          "none",
     "thumbnailDisplayTransitionDuration":  500,
     "thumbnailDisplayInterval":            30,
     "galleryDisplayTransition":            "none",
     "galleryDisplayTransitionDuration":    500,
     "galleryDisplayMode": "rows",
     "thumbnailDisplayOutsideScreen": "false",
     "eventsDebounceDelay": 10,
     "thumbnailL1BorderHorizontal": 0,
     "thumbnailL1BorderVertical": 0,
     "thumbnailLabel": {
        "titleFontSize": "0.6em"
     },
     "thumbnailHoverEffect2": "image_scale_1.00_1.10|label_backgroundColor_rgba(0,0,0,0)_rgba(255,255,255,0)",
     "galleryTheme": {
        "thumbnail": {
            "borderRadius": "8px"
        }
     },
     "thumbnailToolbarImage": {
        "topLeft": "",
        "topRight": "",
        "bottomLeft": "",
        "bottomRight": ""
     },
     "viewerToolbar":   {
        "display": true,
        "standard": "label"
     },
     "viewerTools":     {
        "topLeft":    "pageCounter, playPauseButton",
        "topRight":   "downloadButton, rotateLeft, zoomButton, fullscreenButton, closeButton"
     },
     "viewerGalleryTWidth": 40,
     "viewerGalleryTHeight": 40
}'>
     
<a href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230428141358.png" data-ngThumb="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230428141358.png">exam1</a>
<a href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230428141926.png" data-ngThumb="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230428141926.png">exam 2</a>
<a href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00037-1231245.png" data-ngThumb="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00037-1231245.png"></a>
<a href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00030-1231245.png" data-ngThumb="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00030-1231245.png"></a>
<a href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00206-3876028130.png" data-ngThumb="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/00206-3876028130.png"></a>

</div>
</body>
</html>
<h2 id="参考资料">参考资料</h2>
<ul>
<li><a href="https://stable-diffusion-art.com/prompt-guide/" target="_blank" rel="noopener">Stable Diffusion prompt: a definitive guide - Stable Diffusion Art (stable-diffusion-art.com)</a>
</li>
<li><a href="https://home.gamer.com.tw/artwork.php?sn=5617022" target="_blank" rel="noopener">繪圖AI - Stable Diffusion 相關教學與參考資源 202303 update - yoyojojo的創作 - 巴哈姆特 (gamer.com.tw)</a>
</li>
<li><a href="https://aitag.top/" target="_blank" rel="noopener">魔咒百科词典 (aitag.top)</a>
</li>
<li><a href="https://docs.google.com/spreadsheets/d/16wR5Zg_aQEbxLdrTOrB9cZf8QmsMrJnSGxFKbZVtrKc/edit#gid=329580922" target="_blank" rel="noopener">AI繪圖魔導書 - Google 表格</a>
</li>
<li><a href="https://ref.gamer.com.tw/redir.php?url=https%3A%2F%2Fmajinai.art%2Fzh-tw%2Findex.php" target="_blank" rel="noopener">https://majinai.art/zh-tw/index.php</a>
</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>AIGC03 Stable Diffusion Control Net</title>
      <link>https://aikenh.cn/posts/stablediffusioncontrolnet/</link>
      <pubDate>Wed, 26 Apr 2023 21:19:41 +0000</pubDate>
      <guid>https://aikenh.cn/posts/stablediffusioncontrolnet/</guid>
      <description>Using Control Net to optimize you pic</description>
      <content:encoded><![CDATA[<blockquote>
<p>ControlNet 是 Stable Diffusion 最强力的插件之一，它能够控制 SD 的整个扩散过程，包括让 AI 参考动作/骨架/线条/景深，从而更精准的生成图片。</p>
</blockquote>
<ul>
<li><a href="https://ivonblog.com/posts/stable-diffusion-webui-manuals/extensions/controlnet/" target="_blank" rel="noopener">ControlNet 按照骨架動作繪圖 | Stable Diffusion WebUI使用手冊</a>
</li>
<li><a href="https://ivonblog.com/posts/stable-diffusion-webui-manuals/extensions/posex/" target="_blank" rel="noopener">骨架人偶 PoseX | Stable Diffusion WebUI 使用手冊</a>
</li>
<li><a href="https://ivonblog.com/posts/stable-diffusion-webui-manuals/extensions/latent-couple/" target="_blank" rel="noopener">生成多個人物 Latent Couple | Stable Diffusion WebUI使用手冊</a>
</li>
<li>拓展地址：<a href="https://github.com/Mikubill/sd-webui-controlnet" target="_blank" rel="noopener">Mikubill/sd-webui-controlnet: WebUI extension for ControlNet (github.com)</a>
</li>
<li>ControlNet 地址：<a href="https://github.com/lllyasviel/ControlNet" target="_blank" rel="noopener">lllyasviel/ControlNet: Let us control diffusion models! (github.com)</a>
</li>
<li>模型地址：<a href="https://huggingface.co/lllyasviel/ControlNet-v1-1/tree/main" target="_blank" rel="noopener">lllyasviel/ControlNet-v1-1 at main (huggingface.co)</a>
</li>
</ul>
<h2 id="插件安装和模型下载">插件安装和模型下载</h2>
<blockquote>
<p>AssertionError: extension access disabled because of command line flags
无法在 Listen 模式下安装插件，这是为了安全性考虑。</p>
</blockquote>
<p>插件安装界面安装 ControlNet 的 webui 插件，然后去模型地址下载 ControlNet 的模型，将模型放置在：<code>stable-diffusion-webui/extensions/sd-webui-controlnet/models</code> 目录中，而 CN 其中包含了很多种类，包括：</p>
<ul>
<li>Anime Lineart ：偵測線條，生成的圖片亦會保留原始的線條，適合處理動漫圖像</li>
<li>Canny：偵測圖片邊緣，比較模糊，不如 Scribbles 完整。</li>
<li>Depth：偵測輸入圖片的深度圖(depth map)。</li>
<li>Illumination：偵測輸入圖片的光源與照明效果。</li>
<li><strong>Inpaint：</strong> 功能類似「內補繪製」，使用50%隨機遮罩＋50%隨機光流遮罩訓練而成。</li>
<li>Instruct Pix2Pix 
模型檔名為<code>ip2p</code>，類似「圖生圖」，但是使用訓練50%的指示(instruction)提示詞和50%的敘述(description)提示詞訓練而成。因為是ControlNet，使用此模型時不需要調整CFG Scale。
根據原作者的說法，此模型在下「使其成為X」的提示詞所生成的圖，效果比「使Y成為X」要好。
Also, it seems that instructions like “make it into X” works better than “make Y into X”.</li>
<li>Lineart：偵測線條，適合處理線稿，生成的圖片亦會保留原始的線條。</li>
<li>M-LSD ：偵測輸入圖片的直線。</li>
<li>Normalbae </li>
<li><strong>Openpose：</strong> 使用 OpenPose 技術偵測輸入圖片人物的動作，不一定會保留線條。</li>
<li>Scribbles：偵測線條，偵測到的線條品質介於 Soft Edge 和 Lineart 之間。</li>
<li>Segmentation：模型檔名為 <code>seg</code>，將偵測的圖片物件切成一個一個色塊處理，例如房子一個色塊，後面的天空一個色塊。</li>
<li><strong>Shuffle：</strong> 把輸入圖片的概念轉移到生成的圖片。作者給的例子：輸入灰色裝甲圖片，生成的鋼鐵人盔甲也會是灰色的。</li>
<li>Soft Edge：偵測圖片邊緣，效果較為柔和，像用炭筆塗過。</li>
<li>Tile：輸入圖片，選取一個區域，使其變清晰的模型。</li>
</ul>
<p>模型放置完后，就可以开始使用 ControlNet 插件了。</p>
<h2 id="插件设置和使用">插件设置和使用</h2>
<p>安装完插件和模型后，就能在文生图和图生图部分看到 Control Net 的选项，点击该选项就能进入 ControlNet 的选单，</p>
<p>其中大部分的直接看字面意思就行了，解释一下重要或者难理解的几个：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426222417.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426222417.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426222417.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ul>
<li><strong>Enable</strong> 必须启用</li>
<li><strong>Low VRAM</strong> 降低现存使用，无脑启用</li>
<li><strong>Pixel Perfect</strong> 由 ControlNet 决定预处理的分辨率，无脑启用</li>
<li><strong>Allow Preview</strong> 允许预览，包括线条和骨架，无脑启用</li>
<li><strong>Preprocessor</strong> 预处理器，通常要和模型一致，先将上传的处理过一轮，处理成骨架等线稿，如果图片是白底黑线，则需要选取反转</li>
<li>Control Weight：control 的生效权重</li>
<li>Start/ending step: 开始和结束参与的步数</li>
<li>Loopback，将生成的图像在传回 ControlNet unit</li>
</ul>
<h2 id="posex-使用">PoseX 使用</h2>
<p>可以代替提供图片作为参照，可以自己作画画一个骨架，依赖项：</p>
<ul>
<li>插件：<a href="https://github.com/hnmr293/posex" target="_blank" rel="noopener">hnmr293/posex (github.com)</a>
</li>
<li>openpose 的 controlnet 模型</li>
</ul>
<p>装完插件就可以使用了，在列表中选择 Posex 即可开启调整，选择 send this to controlnet；
然后在 ControlNet 选单中</p>
<ul>
<li>Enable</li>
<li>preprocess：None</li>
<li>Model：openpose</li>
</ul>
<p>其他的照常设置即可，效果如下：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426223026.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426223026.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426223026.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="latent-couple-使用">Latent Couple 使用</h2>
<p>结合 ControlNet 和 PoseX 使用，可以分割提示词，同时绘制多个人，指定不同的提示词和动作。</p>
<p>WorkFlow：</p>
<p>选中选单 -&gt; Enable -&gt; Create Blank Canvas 建立画布 -&gt; 不同颜色鼠标绘制不同区域标识不同个体 -&gt; finish sketch -&gt; fill prompt in for the mask -&gt; prompt info update 会自动上传到提示词窗口</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426223743.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426223743.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426223743.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426223753.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426223753.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426223753.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="fi">FI</h2>
<p>本章节暂时到这，上述的两个插件在不同的场景下的使用是类似的，就不再赘述，本篇主要还是基于参考资料来的，建议查看原文，还有更多的插件推荐和说明。</p>
<p>下一章节主要整理一些 Prompt 相关的写法和资源推荐，最后有时间了再来梳理模型训练和原理。</p>
]]></content:encoded>
    </item>
    <item>
      <title>AIGC02 Stable Diffusion 基础功能介绍</title>
      <link>https://aikenh.cn/posts/stable-diffusion-%E5%9F%BA%E7%A1%80%E4%BD%BF%E7%94%A8/</link>
      <pubDate>Wed, 26 Apr 2023 11:03:56 +0000</pubDate>
      <guid>https://aikenh.cn/posts/stable-diffusion-%E5%9F%BA%E7%A1%80%E4%BD%BF%E7%94%A8/</guid>
      <description>The Basic Function of Stable Diffusion</description>
      <content:encoded><![CDATA[<blockquote>
<p>本篇章介绍关于 Stable DIffusion 的一些基础概念和 WebUI 的基本功能元素，同时介绍一些启动项和模型加载的东西。</p>
</blockquote>
<h2 id="启动项设置局域网">启动项设置（局域网）</h2>
<p>最常用的启动项是 <code>--listen</code>，通过该启动项允许局域网内的其他设备通过 ip 和端口访问部署好的 Stable Diffusion 服务。而设置启动项的方式有以下几种：</p>
<ol>
<li>命令行执行启动脚本的时候携带</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="p">./</span><span class="n">webui</span><span class="p">.</span><span class="py">bat</span> <span class="p">-</span><span class="n">-listen</span>
</span></span><span class="line"><span class="cl"><span class="c"># ./webui.sh --listen</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="2">
<li>修改主入口脚本中的启动选项 <code>vim launch.py</code></li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 修改下面这一行的参数, 将&#34; &#34;中填入需要的参数</span>
</span></span><span class="line"><span class="cl"><span class="c1"># commandline_args = os.environ.get(&#39;COMMANDLINE_ARGS&#39;, &#34;&#34;)</span>
</span></span><span class="line"><span class="cl"><span class="n">commandline_args</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;COMMANDLINE_ARGS&#39;</span><span class="p">,</span> <span class="s2">&#34;--listen&#34;</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="3">
<li>其他的启动项介绍可以参考：<a href="https://ivonblog.com/posts/stable-diffusion-webui-manuals/installation/command-line-arguments-and-settings/" target="_blank" rel="noopener">2.3. 命令列引數 | Stable Diffusion WebUI使用手冊(正體中文)｜Ivon的部落格 (ivonblog.com)</a>
</li>
</ol>
<h2 id="模型相关">模型相关</h2>
<p>提供相关模型下载的网址主要有以下几个：</p>
<ul>
<li><a href="https://civitai.com/" target="_blank" rel="noopener">C站</a>
 |  <a href="https://aimodel.subrecovery.top/" target="_blank" rel="noopener">AI绘画模型博物馆 (subrecovery.top)</a>
 | <a href="https://huggingface.co/" target="_blank" rel="noopener">Hugging Face – The AI community building the future.</a>
</li>
<li><a href="https://rentry.org/sdmodels" target="_blank" rel="noopener">Stable Diffusion Models</a>
 模型百科</li>
<li><a href="https://ref.gamer.com.tw/redir.php?url=https%3A%2F%2Fcyberes.github.io%2Fstable-diffusion-textual-inversion-models%2F" target="_blank" rel="noopener">Stable Diffusion Textual Inversion Embeddings</a>
 Embeding，不建议访问，我个人好像访问了就很卡</li>
<li><a href="https://cyberes.github.io/stable-diffusion-models/#novelai" target="_blank" rel="noopener">Stable Diffusion Models (cyberes.github.io)</a>
 |  <a href="https://home.gamer.com.tw/artwork.php?sn=5617022" target="_blank" rel="noopener">NOVALAI</a>
 该文章中有写，是被黑客泄露的模型</li>
</ul>
<p>这些网站都会提供各种模型的下载，包括 LoRA、Ckpt、HyperNetwork 等。</p>
<h3 id="模型部署和加载">模型部署和加载</h3>
<p>下载完模型后，我们进到如下的目录中，会发现有针对于各种不同模型的子目录(Lora, stable-diffusion, VAE)等</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">cd </span><span class="p">&lt;</span><span class="n">pth</span><span class="p">&gt;/</span><span class="nb">stable-diffusion</span><span class="n">-webui</span><span class="p">/</span><span class="n">model</span><span class="p">/</span><span class="n">models</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>将对应的模型的放到对应的目录中即可，然后重启 stable-diffusion 服务，其会读取路径下的所有模型，在 webui 的对应选项中实现加载。</p>
<p>其中：Ckpt 存放于其中的 stable-diffusion 目录中，是整个生成过程的基础模型，可以在下图所示的地方读取：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230426151334.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230426151334.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230426151334.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>可以看到此处已经加载了诸多我们下载好的 ckpt 模型，并可随意选择和切换。</p>
<p>下面介绍一下各种模型之间的区别：<a href="https://shemmytalk.com/stable-diffusion%E4%B8%AD%E7%9A%84hypernetworks%E6%98%AF%E4%BB%80%E4%B9%88/" target="_blank" rel="noopener">Stable Diffusion中的各种模型</a>
</p>
<h3 id="ckptcheckpoint模型">CKPT（Checkpoint）模型</h3>
<blockquote>
<p>基于某个数据集训练出来的 Stable Diffusion 完整的大模型本身，因此相比于其他的微调模型来说体积一般较大。</p>
</blockquote>
<h3 id="lora-模型">Lora 模型</h3>
<blockquote>
<p><strong>Low-Rank Adaptation of Large Language Models</strong>，直译为大语言模型的低阶适应，为了解决大语言模型微调而开发的一项技术，LoRA 的冻结预训练好的大模型模型参数，然后在每个 Transformer 块里注入可训练的层，大大减少了需要训练的计算量。</p>
</blockquote>
<ul>
<li><a href="https://zhuanlan.zhihu.com/p/610031713" target="_blank" rel="noopener">Stable Diffusion爱好者常说的LoRa是什么？</a>
</li>
<li><a href="https://huggingface.co/blog/lora" target="_blank" rel="noopener">Using LoRA for Efficient Stable Diffusion Fine-Tuning (huggingface.co)</a>
</li>
<li><a href="https://github.com/cloneofsimo/lora" target="_blank" rel="noopener">cloneofsimo/lora: Using Low-rank adaptation to quickly fine-tune diffusion models. (github.com)</a>
</li>
<li><a href="https://arxiv.org/pdf/2106.09685.pdf" target="_blank" rel="noopener">LORA: LOW-RANK ADAPTATION OF LARGE LAN GUAGE MODELS</a>
：官方论文</li>
</ul>
<h3 id="vae-模型">VAE 模型</h3>
<blockquote>
<p><strong>Variational autoencoder</strong>，变分自编码器，负责做隐含空间和 RGB 空间的变换，可以实现添加滤镜和风格的效果，通常来说大模型中会包含该部分变换，不是所有的模型都适合一起使用。</p>
</blockquote>
<h3 id="hypernetwork-网络">Hypernetwork 网络</h3>
<blockquote>
<p>Hypernetwork 是一种微调技术，最初由 Novel AI 开发，他们是 Stable Diffusion 的早期采用者。它是一个小型神经网络，附加在 Stable Diffusion 模型上以修改其风格。插入到噪声预测器 UNet 的交叉注意力模块中，通常情况下，hypernetwork 是一个简单的神经网络：具有 dropout 和激活函数的全连接线性网络。它通过插入两个转换 key 和 query 向量的网络来劫持交叉注意力模块。</p>
</blockquote>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426203046.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426203046.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426203046.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="embedding-嵌入">Embedding 嵌入</h3>
<p>文本嵌入，应该和 HyperNetwork 类似，通过影响 Prompt 的嵌入构建过程来实现特定风格的方法，作为原本网络的拓展组件或者控制器来使用。</p>
<hr>
<p><strong>使用这些模型的地方我们将在下面的页面基本功能元素一起介绍</strong>：这些参数或者模型主要是作为 Additional Network 来使用的，这个我们后续介绍使用的方式，其对 Ckpt 进行进一步的调整，因此不同的搭配使用本身可能会有不同的效果。</p>
<p>需要注意的是，各个模型，各个参数可能都会有各自生成的类型偏向性，一些模型可能是专门过拟合某一些风格，因此用的时候对额外网络的比重调整也是个学问。</p>
<h2 id="基本功能介绍">基本功能介绍</h2>
<blockquote>
<p>加载完基础模型后，就可以试用各个基础功能了，该章节基于文生图的功能每一部分的操作和配置进行介绍，其他的功能会放在后续小节。</p>
</blockquote>
<h3 id="基础结构介绍-basic">基础结构介绍 Basic</h3>
<p>首先从文生图的功能开始介绍，该功能的名字很直观就是通过提供的提示词（Prompt）生成对应的图像，其中控制图片生成的主要有这么几个地方：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230426145447.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230426145447.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230426145447.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ul>
<li><strong>Prompt</strong>：描述生成的图像：图像的内容，质量，风格等；</li>
<li><strong>Negative Prompt</strong>：反向提示词，限定一些边界，生成的图像不会包含这其中的内容；</li>
<li><strong>Sampling</strong>：采样器，实际上不是寻常理解上的采样，而是指的扩散方法，即选用生成图像的扩散模型。</li>
<li><strong>Sampling Steps</strong>：采样步骤，同上实际上指的应该是扩散步骤，可以根据显存来调整该步骤，可以适当调大。</li>
<li><strong>Width、Height</strong>：生成图像的分辨率（Shape &amp; Size）</li>
<li><strong>CFG Scale</strong>：提示词关联程度，和提示词的相关程度</li>
<li><strong>Seed</strong>：随机种子，虽然只是一个随机种子，实际上也会很明显的影响图像生成的样式。</li>
</ul>
<p>设定好了上述对应参数后，就可以点击 Generate 进行图片生成了，右下角的按钮可以将生成的图片转到后续的后处理步骤中，或者保存。</p>
<h3 id="额外模型使用-additional-networks">额外模型使用 Additional Networks</h3>
<p>如果要加载额外的模型参数，比如说要针对模型额外加载 Lora，具体的操作过程如下图所示：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230426164656.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230426164656.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230426164656.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><strong>加载：</strong> 点击 Additional Network 按钮后 -&gt; 会弹出下面一排界面 -&gt; 选择对应需要的模型种类（比如这里选择了 Lora 选项卡）-&gt; 然后选择一个（或者多个）特定的模型 -&gt; 则该 Lora 模型会以 <code>&lt;model:weight&gt;</code> 的形式出现在 Prompt 的地方，这样就完成了额外模型参数的加载了。</p>
<p><strong>调整思路：</strong></p>
<ul>
<li>这里的权重我们通常不会选择 1，从 0.1 开始向上调整是一个比较好的思路。</li>
<li>此外在加载 Lora 的时候，可以参考 C 站中别人和什么 Ckpt 组合使用。</li>
</ul>
<blockquote>
<p>可以看到这里除了 Lora，还有 HyperNetwork 等选项卡，这些可选项都可以使用类似的方式来进行调用。支持同时使用多个，但是权重的调整要自己选择。</p>
</blockquote>
<p>此外如果要使用插件来调整 lora 的比例的话，则需要把 lora 模型放到 <code>/extensions/sd-webui-additional-networks/models/lora</code> 中，这里可以使用超链接的方式，然后在 addition network 选项卡下点击刷新按钮：即可。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230507100209.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230507100209.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230507100209.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="参数搜索功能-scripts">参数搜索功能 Scripts</h3>
<p><a href="https://zhuanlan.zhihu.com/p/600821549" target="_blank" rel="noopener">stable-diffusion-webui prompt语法详解</a>
</p>
<p>由于可供设置的参数数量较多，因此在出一张让人满意的图之前，总免不了各种试，这种时候就需要<strong>参数搜索功能</strong>来简化整个 workflow，我们设置好需要搜索的参数空间，让 Stable Diffusion 自己逐一的遍历每个参数。</p>
<p>webui 中就提供了这样的功能，可以通过 script 实现各种实验的脚本；也就是下图所示的，Script 选项，其中内置的也提供了几种参数搜索的方式：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426193603.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426193603.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426193603.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ol>
<li>非参数搜索）从文件中读取提示词，便于导入导出</li>
<li>提示词搜索（即提示词矩阵）</li>
<li>XYZ Plot，可自定义各种参数的搜索</li>
</ol>
<p><strong>提示词矩阵</strong>功能讲解：用 <code>|</code> 分割 prompt 词，可达到如下的效果，以 <code>a|b</code> 为例，SD 将会生成如下的四种结果：</p>
<p>^a &amp; ^b , a &amp; ^b , b &amp; ^a , a &amp; b</p>
<blockquote>
<p>这里顺便提一嘴，用（prompt）可以强化对提示词的关注程度，(prompt:1.5) 即将该 prompt 的关注程度提升为 150%，[prompt] 则是和(prompt) 相反，则是弱化对提示词的关注程度。</p>
</blockquote>
<p><strong>XYZ Plot</strong>功能讲解：通过设定 2~3 个变量（甚至可以包括模型），可以同时对这三个变量进行排列组合的参数搜索，建议不要把变量范围设置过大，不然搜索空间太大了。</p>
<blockquote>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426195522.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426195522.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426195522.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
</blockquote>
<p>在 XYZ 中选择好对应的变量后，在对应的值选框中，用 <code>,</code> 分割可选的各个变量即可开始进行搜索，最后的结果大概如下，便于让我们找出合适的参数。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426195710.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426195710.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426195710.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="其他功能介绍">其他功能介绍</h2>
<blockquote>
<p>基于上述对于字生图的功能介绍，基础的功能就大概了解了，接下来拓展介绍一下其他的功能。</p>
</blockquote>
<h3 id="图生图功能">图生图功能</h3>
<blockquote>
<p>图生图的定位是，基于提示词对原图进行重绘改造，核心参数是重绘强度。也可以在文生图之后送到图生图模块中进行逐步的迭代优化。</p>
</blockquote>
<p>参考资料：<a href="https://zhuanlan.zhihu.com/p/616895208?utm_id=0" target="_blank" rel="noopener">5分钟学会Stable Diffusion图生图功能</a>
</p>
<p>这里有个新的<strong>核心可配置项</strong>为：</p>
<ul>
<li><strong>Denoising Strength（重绘强度）</strong>： 也就是偏离原图的程度，越大和原图越不相似，较常取值于 0.6-0.7 之间</li>
<li>同时要注意调整 Size 和原图保持一致，不然原图会被拉伸。</li>
</ul>
<p>新功能：同时这里也存在两个模型可以帮助我们根据原图去<strong>反向推演提示词</strong>，上传完图片之后点击这两个其中一个即可反向推演出 Prompt 供我们参考（但是对于生成一个好图还远远不够）：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426210352.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426210352.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230426210352.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>剩下的和文生图一致，就可以基于我们的图片和提示词去生成一张新的图片。</p>
<p>这里还有一些其他的功能做一下简单介绍：</p>
<ul>
<li><strong>Sketch</strong>：涂鸦绘制，给一张涂鸦和 Prompt 去生成一个新的图片（可以用于作画），会保留草图的颜色信息</li>
<li><strong>Inpaint</strong>：局部绘制，涂抹原图中的部分，并只对该部分进行重新生成，可以换风格，换图案，换脸，换衣服之类的，可以选择重绘蒙版部分或者非蒙版部分的内容，也可以调整蒙版的模糊程度</li>
<li><strong>Inpaint sketch</strong>：两者的结合体，会保留颜色信息进行重绘</li>
<li>&hellip;</li>
</ul>
<h3 id="高清化功能">高清化功能</h3>
<p>简单理解就是超分辨率和面部重建等重建图片质量的一系列模型，无需过多介绍。</p>
<h3 id="图像信息">图像信息</h3>
<p>应该是提取生成图的信息。</p>
<h2 id="fi">FI</h2>
<p>本篇章就到这里结束，下一章节会讲一下 Control Net，有时间的话会去淘一下有没有什么插件值得讲解的。本篇章中有希望进一步详细或者让我去了解的也可以留言。</p>
]]></content:encoded>
    </item>
    <item>
      <title>Windows Configuration05 CUDA &amp; Cudnn</title>
      <link>https://aikenh.cn/posts/windowscudacudnn/</link>
      <pubDate>Mon, 24 Apr 2023 09:50:01 +0000</pubDate>
      <guid>https://aikenh.cn/posts/windowscudacudnn/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;在 Windows 和 WSL2 中安装 Cuda 和 Cudnn ，是配置 GPU 开发环境中重要的一步，其支撑了 AI 模型进行 Training 和 Interface 。本篇介绍安装 CUDA 和 Cudnn 的步骤和一些踩过的坑。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;参考资料如下：&lt;a href=&#34;https://blog.csdn.net/halou10200912/article/details/106048719&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;版本查看&lt;/a&gt;
 | &lt;a href=&#34;https://zhuanlan.zhihu.com/p/99880204&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Win 安装 Cuda 和cuDNN&lt;/a&gt;
 | &lt;a href=&#34;https://blog.csdn.net/Apple_Coco/article/details/129293019&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;WSL 2 安装 CUDA 和cuDNN&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id=&#34;win-11-安装-cuda-和-cudnn&#34;&gt;Win 11 安装 CUDA 和 cuDNN&lt;/h2&gt;
&lt;h3 id=&#34;cuda&#34;&gt;CUDA&lt;/h3&gt;
&lt;p&gt;首先在 Nvidia 的控制面板：&lt;strong&gt;帮助-系统信息&lt;/strong&gt;的如下位置，查看 GPU 最大支持的 CUDA 版本：&lt;/p&gt;
&lt;p&gt;
&lt;div class=&#34;post-img-view&#34;&gt;
  &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230424130608.png&#34;&gt;
    &lt;img alt=&#34;image.png&#34; loading=&#34;lazy&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230424130608.png&#34;class=&#34;responsive-image&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230424130608.png&#34; style=&#34;display: block; margin: 0 auto;&#34;
      alt=&#34;image.png&#34;  /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;script&gt;
  document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
      var images = document.querySelectorAll(&#34;.responsive-image&#34;);
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + &#34;px&#34;;
      });
  });
&lt;/script&gt;
&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p>在 Windows 和 WSL2 中安装 Cuda 和 Cudnn ，是配置 GPU 开发环境中重要的一步，其支撑了 AI 模型进行 Training 和 Interface 。本篇介绍安装 CUDA 和 Cudnn 的步骤和一些踩过的坑。</p>
</blockquote>
<p>参考资料如下：<a href="https://blog.csdn.net/halou10200912/article/details/106048719" target="_blank" rel="noopener">版本查看</a>
 | <a href="https://zhuanlan.zhihu.com/p/99880204" target="_blank" rel="noopener">Win 安装 Cuda 和cuDNN</a>
 | <a href="https://blog.csdn.net/Apple_Coco/article/details/129293019" target="_blank" rel="noopener">WSL 2 安装 CUDA 和cuDNN</a>
</p>
<h2 id="win-11-安装-cuda-和-cudnn">Win 11 安装 CUDA 和 cuDNN</h2>
<h3 id="cuda">CUDA</h3>
<p>首先在 Nvidia 的控制面板：<strong>帮助-系统信息</strong>的如下位置，查看 GPU 最大支持的 CUDA 版本：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230424130608.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230424130608.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230424130608.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>也可以使用 Nvidia-smi 命令在 Powershell 或者 CMD 中查看:</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230424130700.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230424130700.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230424130700.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>确定了版本之后到 <a href="https://developer.nvidia.com/cuda-downloads" target="_blank" rel="noopener">Nvidia CUDA下载页面</a>
 下载指定版本的 CUDA 进行安装（根据安装指引进行）即可，安装位置等默认即可，其中有一些安装选项即是 Nvidia GeForce Experience 安装的内容。</p>
<p>安装完成后在 CMD 或者 PowerShell 确认是否安装完成（需要重启终端）：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">nvcc</span> <span class="n">-V</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230424131341.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230424131341.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230424131341.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>显示如上信息可看到指定的版本已经安装成功，然后我们可以在 CMD 中执行如下命令来获取安装地址/设置环境变量：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">set </span><span class="n">cuda</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230424131612.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230424131612.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230424131612.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>完成这些后我们就可以开始安装 CuDNN 了，CuDNN 的安装需要我们记住 Cuda 的安装地址。</p>
<h3 id="cudnn">cuDNN</h3>
<p>在 Nvidia 官网注册账号，并在 <a href="https://developer.nvidia.com/rdp/cudnn-download" target="_blank" rel="noopener">cuDNN 下载界面</a>
下载对应版本的 Package 后，讲 Package 中各个目录下的内容放到 CUDA 文件夹的对应目录下即可。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230424132305.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230424132305.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230424132305.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>即 <code>mv cuDNN/lib/* CUDA/lib/*</code> &hellip;；拷贝完成后可以执行 CUDA 中自带的校验工具查看安装情况：</p>
<ul>
<li>/cuda/extras/demo_suite/deviceQuery.exe</li>
<li>/cuda/extras/demo_suite/bandwidthTest.exe</li>
</ul>
<p>可以看到验证详细结果和是否通过。</p>
<h2 id="wsl-2-配置-cuda-和-cudnn">WSL 2 配置 CUDA 和 cuDNN</h2>
<p>建议可以先看看： <a href="https://docs.nvidia.com/cuda/wsl-user-guide/index.html#cuda-support-for-wsl-2" target="_blank" rel="noopener">NVIDIA GPU Accelerated Computing on WSL 2</a>
</p>
<p>新版的 WSL 2 对于 GPU 的支持已经相当的友善，能够直接调用 Windows 的 GPU，但是在使用过程前还是需要对环境进行一定的配置。具体分为以下的两步：</p>
<ol>
<li>安装 cuda-toolkit：注意不能重复安装 CUDA 驱动，避免和 Windows 系统的 CUDA 驱动产生冲突</li>
<li>安装 cuDNN</li>
<li>（非必须）设置环境变量</li>
</ol>
<p>以下以 Ubuntu WSL 2 为例，介绍以下具体的安装过程。</p>
<h3 id="cuda-toolkit-on-wsl-2">CUDA-toolkit on WSL 2</h3>
<p>通过 <a href="https://developer.nvidia.com/cuda-downloads?target_os=Linux&amp;target_arch=x86_64&amp;Distribution=WSL-Ubuntu&amp;target_version=2.0" target="_blank" rel="noopener">Nvidia 的官方下载页面</a>
选择 WSL-Ubuntu 即可找到对应的安装工具，我们这里选择 runfile 的方式进行，按照官方给出的安装指令进行，即：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230424133107.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230424133107.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230424133107.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">wget https://developer.download.nvidia.com/compute/cuda/12.1.1/local_installers/cuda_12.1.1_530.30.02_linux.run
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">sudo sh cuda_12.1.1_530.30.02_linux.run</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>下载对应的 run 包后执行安装即可。</p>
<h3 id="cudnn-on-wsl-2">cuDNN on WSL 2</h3>
<p>在 Ubuntu 上安装 cuDNN 实际上除了网上资料很多的下载包进行安装，直接用以下的方式进行安装即可。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt install nvidia-cudnn</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>安装后执行 nvcc &ndash;version 验证版本。</p>
<h3 id="env">Env</h3>
<blockquote>
<p>这一块的设置好像目前已经是不需要的，首先可以尝试不配置这一块内容。以下我会给出我这边的配置</p>
</blockquote>
<p>环境配置这块好像并不需要执行，如果还是报错的话，可以按照以下的方式来配置 zshrc 或者 bashrc。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">CPATH</span><span class="o">=</span>/usr/local/cuda/include:<span class="nv">$CPATH</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">LD_LIBRARY_PATH</span><span class="o">=</span>/usr/local/cuda/lib64/:<span class="nv">$LD_LIBRARY_PATH</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">PATH</span><span class="o">=</span>/usr/local/cuda/bin:<span class="nv">$PATH</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">CUDA_ROOT</span><span class="o">=</span>/usr/local/cuda</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>or</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">LD_LIBRARY_PATH</span><span class="o">=</span>/usr/local/cuda-12.1/lib64/<span class="o">{</span>LD_LIBRARY_PATH:+:<span class="o">{</span>LD_LIBRARY_PATH<span class="o">}}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这里顺便给出一个路径 /usr/lib/wsl/lib 中会有相关的 so 文件的路径，应该是和主机互通的地方。</p>
<h2 id="报错分析">报错分析</h2>
<p>Could not load library libcudnn_cnn_infer.so.8. Error: libcuda.so: cannot open shared object file: N</p>
<blockquote>
<p>没有安装或者配置 cudnn</p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>AIGC01 Stable Diffusion and midjourney Setup</title>
      <link>https://aikenh.cn/posts/stable-diffusion/</link>
      <pubDate>Wed, 19 Apr 2023 16:00:00 +0000</pubDate>
      <guid>https://aikenh.cn/posts/stable-diffusion/</guid>
      <description>Intro on How to Set up and use it.</description>
      <content:encoded><![CDATA[<blockquote>
<p>This Chapter introduce how to set up stable diffusion and mid-journey, and record some problem I meet when I deploy it.</p>
</blockquote>
<h2 id="deprecated-midjourney">(Deprecated) midjourney</h2>
<blockquote>
<p>由于 midjourney 现需要付费使用，同时没有开源，因此我们讲一笔带过该部分内容，该部分内容大多转载于  <a href="https://www.uisdc.com/midjourney" target="_blank" rel="noopener">超详细！AI 绘画神器 Midjourney 基础使用手册</a>
</p>
</blockquote>
<p><a href="https://midjourney.com/home/?callbackUrl=%2Fapp%2F" target="_blank" rel="noopener">midjourney</a>
 的安装步骤主要分成以下的几步：</p>
<ol>
<li>点击 Join the Beta 注册账号，注册完会跳转到；</li>
<li>Discord 首页，亲自创建自己的服务器，仅供我和我的朋友使用；</li>
<li>下载客户端，在默认对话界面讯在或开始新的对话，输入 Midjourney Bot，添加到服务器</li>
<li>付费开启体验。</li>
</ol>
<h2 id="deprecated-dreamstudio">(Deprecated) DreamStudio</h2>
<blockquote>
<p>说是可以本地部署，但是实际体验非常不好，应该只是部署了 Webui，然后调用官方提供的免费 API；所以有时候生成不出来，但是又不报错，不知道是不是使用姿势有问题，反正很屎。</p>
</blockquote>
<ul>
<li><a href="https://github.com/Stability-AI/StableStudio" target="_blank" rel="noopener">https://github.com/Stability-AI/StableStudio</a>
</li>
<li>装好 npm 和 yarn</li>
<li>参考 quick start，git clone -&gt; (cd) yarn 安装 -&gt; yarn dev 部署在本地端口上。</li>
<li>官网注册账号-&gt; 获取 API -&gt; 填入并在最上方转到 Generate 页面即可。</li>
</ul>
<h2 id="stable-diffusion-部署专题">Stable Diffusion 部署专题</h2>
<blockquote>
<p>该部分作为 Intro，仅介绍 Stable Diffusion 的安装和部署，以及一些启用参数等，具体的使用在后面的文章进行进一步的讲解。</p>
</blockquote>
<p><strong>基于官方 REPO</strong>： <a href="https://github.com/AUTOMATIC1111/stable-diffusion-webui" target="_blank" rel="noopener">AUTOMATIC1111/stable-diffusion-webui: Stable Diffusion web UI (github.com)</a>
</p>
<p>这里介绍基于 windows 的安装和 WSL2 的安装部署过程。整体的安装可能会分成以下的几个步骤进行：（推荐在安装和部署之前，参考 [[Published发布/WindowsCudaCudnn]] 一文，首先配置 CUDA，也可以遇到问题再部署）</p>
<ul>
<li>基础依赖和环境安装（python、CUDA）</li>
<li>Stable DIffusion 的 UI 界面和部分插件安装</li>
<li>模型下载和加载</li>
</ul>
<!--More-->
<h3 id="win-部署">Win 部署</h3>
<blockquote>
<p>一些像是 Conda 之类的包的安装这里都不会再赘述，可以参考相关文章 [[Published发布/python_pack_manager]]，这一部分仅针对 Stable Diffusion 的安装进行描述</p>
</blockquote>
<ol>
<li>(optional) 创建 Conda 环境，避免依赖冲突和污染，envname 可以是你自选的一个环境名。</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">conda</span> <span class="n">create</span> <span class="n">-n</span> <span class="p">&lt;</span><span class="n">envname</span><span class="p">&gt;</span> <span class="n">python</span><span class="p">=</span><span class="mf">3.10</span><span class="p">.</span><span class="mf">6</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="2">
<li>下载 stable-diffusion-webui 仓库, 会将该 repo 下载到当前目录，即 <code>./stable-diffusion-webui/</code></li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">git</span> <span class="n">clone</span> <span class="n">https</span><span class="err">:</span><span class="p">//</span><span class="n">github</span><span class="p">.</span><span class="n">com</span><span class="p">/</span><span class="n">AUTOMATIC1111</span><span class="p">/</span><span class="nb">stable-diffusion</span><span class="n">-webui</span><span class="p">.</span><span class="n">git</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="3">
<li><del>安装 python 依赖的过程已经集成在启动脚本中，因此无需执行依赖安装</del></li>
</ol>
<blockquote>
<p>xformers 可能需要手动安装，并且需要额外的启动参数，安装脚本如下 <code>pip install -U xformers</code></p>
</blockquote>
<ol start="4">
<li>
<p>（已安装就忽略）安装 cuda，cudnn，参考相关文章</p>
</li>
<li>
<p>启动网页客户端进行使用和测试
- 其中如果带 listen 参数的话可以开启局域网访问。
- 带 share （不推荐）可通过 python 的库托管，会给定一个公网 url，支持进行公网访问。
- 带 xformers 可以在 webui 中启用 xformer，手动先安装一下</p>
</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="p">./</span><span class="nb">web-ui</span><span class="p">.</span><span class="py">bat</span> <span class="p">-</span><span class="n">-listen</span> <span class="p">-</span><span class="n">-xformers</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>或者直接双击运行即可。</p>
<h3 id="wsl-2-部署">WSL 2 部署</h3>
<blockquote>
<p>这里的部署也可以作为 LINUX 部署的方式，实际上安装的过程和 windows 是相似的，只是最后启动的脚本不同。</p>
</blockquote>
<p>其中 1~4 的步骤都是类似的，cuda 安装参考相关文章中 WSL2 专题即可；最后的执行脚本如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo ./webui.sh -f</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这样执行的原因是可能会提示不是 root 用户，使用-f 参数强制其运行，并通过 sudo 避免访问受限。</p>
<h3 id="docker-部署">Docker 部署</h3>
<p>参考资料：<a href="https://zhuanlan.zhihu.com/p/614421868" target="_blank" rel="noopener">Docker版Stable Diffusion WebUI，可cpu运行</a>
</p>
<p>Docker Image：<a href="https://github.com/AbdBarho/stable-diffusion-webui-docker" target="_blank" rel="noopener">AbdBarho/stable-diffusion-webui-docker: Easy Docker setup for Stable Diffusion with user-friendly UI (github.com)</a>
</p>
<p>安装的时候记得使用 -v 将 model 和 output 目录挂载出来，方便后续下载模型以及下载图片。</p>
<p>参考的启动脚本如下（WSL 2）：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>docker</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-docker" data-lang="docker"><span class="line"><span class="cl">docker run -it --name sdw --network host <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  -v /mnt/d/software/ai/stable-diffusion-webui/models:/app/stable-diffusion-webui/models <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  -v /mnt/d/software/ai/stable-diffusion-webui/outputs:/app/stable-diffusion-webui/outputs <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  --rm siutin/stable-diffusion-webui-docker <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  bash webui.sh --skip-torch-cuda-test --precision full --no-half --use-cpu Stable-diffusion GFPGAN ESRGAN VAE --all --share</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>后续有空的话会修改一下，或者给出 compose 文件。</p>
<h2 id="插件安装和设置">插件安装和设置</h2>
<p>插件安装，下列位置 URL 填入 Github 地址，点击安装后重启 UI 即可。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230425125811.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230425125811.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230425125811.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ul>
<li><strong>Addition Net Work</strong>插件：<a href="https://github.com/kohya-ss/sd-webui-additional-networks" target="_blank" rel="noopener">kohya-ss/sd-webui-additional-networks (github.com)</a>
</li>
<li><strong>中文插件安装和设置</strong>：<a href="https://github.com/VinsonLaro/stable-diffusion-webui-chinese" target="_blank" rel="noopener">VinsonLaro/stable-diffusion-webui-chinese: stable-diffusion-webui 的汉化版本 (github.com)</a>
</li>
</ul>
<p>中文插件的启用主要在 Setting 选项卡中，用户界面的最下面，选择后保存（Apply Setting）并重载 UI （Reload Web UI）即可。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230425125945.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230425125945.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230425125945.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="插件更新其他安装方式">插件更新&amp;其他安装方式</h3>
<p>直接到 extensions 目录下进行 git clone、git pull 或者下载安装包来进行解压都可以。</p>
<h2 id="安装问题汇总">安装问题汇总</h2>
<p><strong>Something went wrong Expecting value: line 1 column 1 (char 0)</strong> ： 该错误和代理有关，关闭或者重启部分代理设置可解决。</p>
<p><strong>虚拟环境启动失效的问题</strong>：删除 wsl2 中 stable-diffusion-webui 目录下的虚拟环境目录，重新执行即可。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">rm -rv venv</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="fi-后续安排">FI 后续安排</h2>
<p>部署的部分到这里就结束了，之后的篇章会如下安排，时间未定，有时间的话会写：</p>
<ul>
<li>基础的使用：页面和基本功能元素、各种模型的介绍、载入和使用、以及各种启动项的介绍；</li>
<li>插件和拓展：Control Net 和部分插件专题</li>
<li>训练：提供自己的图像训练自己的模型</li>
<li>Prompt：整理 Prompt 资源，归纳自己用的 Prompt、Prompt 小技巧</li>
<li>not sure）原理：Stable Diffusion 的论文原理和代码解读</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Grep、Sed、Awk 03 Awk</title>
      <link>https://aikenh.cn/posts/linux%E4%B8%89%E5%89%91%E5%AE%A2%E4%B9%8Bawk/</link>
      <pubDate>Tue, 18 Apr 2023 16:00:07 +0000</pubDate>
      <guid>https://aikenh.cn/posts/linux%E4%B8%89%E5%89%91%E5%AE%A2%E4%B9%8Bawk/</guid>
      <description>Linux 三剑客之Awk</description>
      <content:encoded><![CDATA[<blockquote>
<p>Linux 三剑客之 Awk (由三个创始人的姓氏首字母组成)，相比于 Grep 和 Sed 而言更为特殊一些，它是一种模式匹配的编程语言，其主要的作用匹配文本进行处理，其擅长实现对文本的格式化输出，而作为一门编程语言：支持函数，变量，循环，运算，但相对简单。</p>
</blockquote>
<p>AWK 的执行逻辑是：搜索文件的每一行，如果<strong>发现匹配内容，就执行下一个编程步骤，如果没发现，就继续处理下一行</strong>的内容。</p>
<h2 id="intro">Intro</h2>
<blockquote>
<p>由于 AWK 实际上是一个编程语言，本篇主要只介绍其命令行用法。</p>
</blockquote>
<p>首先介绍 AWK 命令，其主要用于匹配文本并格式化输出，适用于对<strong>表格</strong>化的数据机型处理。其使用模板大致如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">awk <span class="o">[</span>options<span class="o">]</span> <span class="s1">&#39;program&#39;</span> <span class="nv">var</span><span class="o">=</span>value file...
</span></span><span class="line"><span class="cl">awk <span class="o">[</span>options<span class="o">]</span> <span class="s1">&#39;pattern {action1; action2; ...}&#39;</span> file ...
</span></span><span class="line"><span class="cl">awk <span class="o">[</span>options<span class="o">]</span> -f programfile <span class="nv">var</span><span class="o">=</span>value file...
</span></span><span class="line"><span class="cl">awk <span class="o">[</span>options<span class="o">]</span> <span class="s1">&#39;BEGIN{ action;... } pattern{ action;... } END { action;... }&#39;</span> file ...</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li><strong>-f</strong> scriptfile: 从脚本文件中读取 awk 命令</li>
<li><strong>-v</strong> var=value: 赋值一个用户定义变量，也可用这种方式修改内置变量</li>
<li><strong>-F</strong> fs: fs 可为任意字符串或者正则表达式，用于指定分隔符（也可以通过-v 的方式修改内置的分隔符变量来实现）</li>
</ul>
<p>每个 action 或者说 statement 之间用 <code>；</code> 分割</p>
<p>参考资料：<a href="https://zh.wikipedia.org/wiki/AWK" target="_blank" rel="noopener">AWK wikipedia</a>
 | <a href="https://github.com/EZLippi/practical-programming-books/blob/master/src/awk.md" target="_blank" rel="noopener">practical-programming-books/awk.md </a>
 | <a href="https://awk.readthedocs.io/en/latest/chapter-one.html" target="_blank" rel="noopener">一. AWK入门指南 — AWK程序设计语言</a>
 | <a href="https://www.cnblogs.com/along21/p/10366886.html" target="_blank" rel="noopener">Linux文本三剑客超详细教程&mdash;grep、sed、awk - alonghub</a>
</p>
<h2 id="variant-变量">Variant 变量</h2>
<p><strong>变量</strong>：awk 主要涵盖两种变量，变量和内置变量，定义变量使用-v 命令，在每个变量前都要加 <code>-v</code></p>
<p>接下来分别介绍如何使用这些变量来对文件进行操作。</p>
<h3 id="内置变量">内置变量</h3>
<blockquote>
<p>awk 进行文件处理的时候，会有一组默认变量，基于这组默认变量可以支持各种脚本需求，同时也对应一些操作。</p>
</blockquote>
<table>
  <thead>
      <tr>
          <th>内置变量</th>
          <th>功能</th>
          <th>默认值</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>FS</td>
          <td>分割符变量</td>
          <td>&quot;&quot;</td>
      </tr>
      <tr>
          <td>OFS</td>
          <td>输出时的字段分隔符</td>
          <td>&quot;&quot;</td>
      </tr>
      <tr>
          <td>NF</td>
          <td>分割后的字符串数量(可以被分成几段)，<code> $NF</code> 引用最后一列；<code>$ (NF-1)</code> 引用倒数第二列</td>
          <td></td>
      </tr>
      <tr>
          <td>NR</td>
          <td>行号；后跟多个文件时，第二个文件的行号从第一个的末尾开始</td>
          <td></td>
      </tr>
      <tr>
          <td>FNR</td>
          <td>行号；但各个文件分别计数</td>
          <td></td>
      </tr>
      <tr>
          <td>FILENAME</td>
          <td>当前文件名</td>
          <td></td>
      </tr>
      <tr>
          <td>ARGC</td>
          <td>命令行参数的个数</td>
          <td></td>
      </tr>
      <tr>
          <td>ARGV</td>
          <td>数组，存储了命令行给定的各个参数</td>
          <td></td>
      </tr>
      <tr>
          <td>RS</td>
          <td>指定输入时的换行符，（原换行符效果保留）</td>
          <td></td>
      </tr>
      <tr>
          <td>ORS</td>
          <td>替代输出时的换行符</td>
          <td></td>
      </tr>
  </tbody>
</table>
<p>接下来我会用简单的例子来说明以下这些指令，基于以下的测试文件 <code>awk_test</code>：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">hello:awk:world
</span></span><span class="line"><span class="cl">good-for-u
</span></span><span class="line"><span class="cl">the:env:basic:on:bash
</span></span><span class="line"><span class="cl">fi:example</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>第一个<strong>主要参数的例子</strong>如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">awk -v <span class="nv">FS</span><span class="o">=</span><span class="s2">&#34;:&#34;</span> -v <span class="nv">OFS</span><span class="o">=</span><span class="s2">&#34;|&#34;</span> <span class="s1">&#39;print{$0,NF,NR,FILENAME,ARGC}&#39;</span> awk_test
</span></span><span class="line"><span class="cl"><span class="c1">#BTW等同于如下的文件</span>
</span></span><span class="line"><span class="cl">awk -F<span class="s2">&#34;:&#34;</span> -v <span class="nv">OFS</span><span class="o">=</span><span class="s2">&#34;|&#34;</span> <span class="s1">&#39;{print $0,NF,NR,FILENAME,ARGC,ARGV[3]}&#39;</span> awk_test</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>该命令将输出如下结果，各个参数的含义可以在上面查表。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">hello:awk:world|3|1|awk_test|2
</span></span><span class="line"><span class="cl">good-for-u|1|2|awk_test|2
</span></span><span class="line"><span class="cl">the:env:basic:on:bash|5|3|awk_test|2
</span></span><span class="line"><span class="cl">fi:example|2|4|awk_test|2</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><blockquote>
<p><code> $n</code> 代表指定列，如果是 <code>$ 0</code> 就会输出每一列。</p>
</blockquote>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ARGV<span class="o">[</span>i<span class="o">]</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>上述对应第 i 个参数。</p>
<p>第二个介绍<strong>NF 的特殊用法</strong>：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">awk -F<span class="s2">&#34;:&#34;</span> -v <span class="nv">OFS</span><span class="o">=</span><span class="s2">&#34;|&#34;</span> <span class="s1">&#39;{print $(NF-1)}&#39;</span> awk_test</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>会得到如下的输出：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">awk
</span></span><span class="line"><span class="cl">good-for-u
</span></span><span class="line"><span class="cl">on
</span></span><span class="line"><span class="cl">fi</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>基于上面的例子也能对 print 命令的使用有个大致的概念。</p>
<h3 id="自定义变量">自定义变量</h3>
<blockquote>
<p>这里主要介绍自定义变量的几种方式，</p>
</blockquote>
<p>Way 1: 直接通过输入参数设置好变量值 <code>-v var=value</code>
Way 2: 在 program 中定义
- <code>awk -F':' {name=&quot;admin&quot;; print name, $0}</code> 一切正常
- <code>awk -F':' {print name, $0;name=&quot;admin&quot;}</code> 第一行的 name 会为空</p>
<h3 id="数组">数组</h3>
<p>（1）可使用任意字符串；字符串要使用双引号括起来
（2）如果某数组元素事先不存在，在引用时，awk 会自动创建此元素，并将其值初始化为“空串”
（3）若要判断数组中是否存在某元素，要使用“index in array”格式进行<strong>遍历</strong>
（4）若要<strong>遍历数组中的每个元素</strong>，要使用 for 循环<strong>for(var in array)</strong> {for-body}</p>
<p>这里简单介绍一下数组的使用，<code>{ line[NR] = $0 }  # 记下每个输入行</code> ，<code>!arr[$ 0]++</code> 去除重复元素，并对每个元素出现的次数进行计数。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 反转 - 按行逆序打印输入</span>
</span></span><span class="line"><span class="cl">    <span class="o">{</span> line<span class="o">[</span>NR<span class="o">]</span> <span class="o">=</span> <span class="nv">$0</span> <span class="o">}</span>  <span class="c1"># 记下每个输入行</span>
</span></span><span class="line"><span class="cl">END <span class="o">{</span> <span class="nv">i</span> <span class="o">=</span> NR           <span class="c1"># 逆序打印</span>
</span></span><span class="line"><span class="cl">      <span class="k">while</span> <span class="o">(</span>i &gt; 0<span class="o">)</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">        print line<span class="o">[</span>i<span class="o">]</span>
</span></span><span class="line"><span class="cl">        <span class="nv">i</span> <span class="o">=</span> i - <span class="m">1</span>
</span></span><span class="line"><span class="cl">      <span class="o">}</span>
</span></span><span class="line"><span class="cl">    <span class="o">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">---打印文件内容，和该行重复第几次出现
</span></span><span class="line"><span class="cl">awk <span class="s1">&#39;{!arr[$0]++;print $0,arr[$0]}&#39;</span> awktest</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>下面将 value 赋值给数组下标为 index 的元素：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">array<span class="o">[</span>index<span class="o">]=</span>value</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="printf-命令">Printf 命令</h2>
<blockquote>
<p>比 print 更强大的专注于格式化的输出命令，而 FORMAT 也是 AWK 的一个重要核心，所以这里额外的介绍以下 printf，并以此引入FORMAT</p>
</blockquote>
<p>其使用方式大致如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">printf</span> <span class="s2">&#34;FORMAT&#34;</span>, item1,item2,...</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>同时相比于 print，其具备如下特性需要注意：</p>
<ol>
<li>FORMAT 必须指定；</li>
<li>不会自动换行，需要显式的给出换行控制符，<code>\n</code></li>
<li>FORMAT 需要为后面的每个 item（如 $1, $ 2 等需要输出的变量） 指定格式符</li>
</ol>
<h3 id="格式写法">格式写法</h3>
<blockquote>
<p>format 的定义得与 item 相互一一对应，下面是一些格式的写法。</p>
</blockquote>
<ul>
<li><code>%c</code>：显示字符的 ASCII 码</li>
<li><code>%d</code>，<code>%i</code>：显示十进制整数</li>
<li><code>%e</code>，<code>%E</code>：显示科学计数法数值</li>
<li><code>%f</code>：显示为浮点数，小数：<code>%5.1f</code> 指的是带小数点，宽度共 5 位，其中小数 1 位，不够的情况用空格补上。</li>
<li><code>%g</code>，<code>%G</code>：以科学计数法或者浮点形式显示数值</li>
<li><code>%s</code>：显示字符串，例如 <code>%5s</code>，显示最少 5 个字符，不够用空格补上，超过还继续显示</li>
<li><code>%u</code>：无符号整数</li>
<li><code>%%</code>：显示%本身</li>
</ul>
<blockquote>
<p>除了这些字符格式之外，还有一类修饰词，用来规范输出的样式，修饰词放 <code>%&lt;修饰词&gt;&lt;格式写法&gt;</code></p>
</blockquote>
<ul>
<li><code>&lt;digit&gt;[.&lt;digit&gt;]</code>：<code>&lt;digit&gt;</code> 表示数字，第一个数字控制显示的宽度，第二个表示小数点后的精度。</li>
<li><code>-</code>：左对齐（默认右对齐），<code>%-15s</code> 左对齐显示 15 个字符</li>
<li><code>+</code>：显示数值的正负符号，<code>%+d</code></li>
</ul>
<p>举个例子，假如我们有如下的 person_info 文件</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">ponywang 123456
</span></span><span class="line"><span class="cl">hollyx 234567</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>则使用该 awk 命令</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">awk <span class="s1">&#39;{printf &#34;%10s:%11s\n&#34;, $1, $2}&#39;</span> contract</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>输出如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">  ponywang:     123456
</span></span><span class="line"><span class="cl">    hollyx:     234567</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>而如果约定左对齐的话，即使用下条 awk 命令，对应的结果如下</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">awk <span class="s1">&#39;{printf &#34;%-10s:%11s\n&#34;, $1, $2}&#39;</span> contract
</span></span><span class="line"><span class="cl">ponywang  :     <span class="m">123456</span>
</span></span><span class="line"><span class="cl">hollyx    :     <span class="m">234567</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="operator-基本操作符">Operator 基本操作符</h2>
<blockquote>
<p>各种<strong>算数操作符</strong>、<strong>比较操作符</strong>、<strong>逻辑操作符</strong>，和普通的操作符是一致的，就不在赘述了；而字符串操作符是无符号操作符，做字符串连接。这里介绍一些其他的特别的操作符。</p>
</blockquote>
<ul>
<li>赋值操作符：
<ul>
<li><code>=</code>，<code>+=</code>，<code>-=</code>，<code>*=</code>，<code>/=</code>，<code>%=</code>，<code>^=</code></li>
<li><code>++</code> ，<code>--</code></li>
</ul>
</li>
<li>模式匹配符：
<ul>
<li><code>~</code>：左边是否和右边匹配</li>
<li><code>!~</code>：是否不匹配</li>
</ul>
</li>
<li>函数操作符：<code>function_name(arg1, arg2)</code></li>
<li>三目表达式：selector?if-true-expression:if-false-expression</li>
</ul>
<p>（<strong>三目表达式使用</strong>）例子 1：在未使用的 drive 的行面前添加 null，否则添加 nonull，该例子实际上包含了赋值和三目表达式。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">df -h <span class="p">|</span> awk <span class="s1">&#39;{$3==0?name=&#34;null&#34;:name=&#34;nonull&#34;;print name,$0}&#39;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>（<strong>模式匹配符使用</strong>）例子 2：仅打印 dev 的磁盘，有以下的两种匹配方式：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">df -h <span class="p">|</span> awk <span class="s1">&#39;/^\/dev/ {print $0}&#39;</span>
</span></span><span class="line"><span class="cl">df -h <span class="p">|</span> awk <span class="s1">&#39;$1 ~ /^\/dev/ {print $0}&#39;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>其中可以用模式匹配符结合$n 来指定在哪一列中进行匹配。</p>
<blockquote>
<p>同时我们可以看出 awk 和管道结合使用的方式，那么如果我们要过滤出 dev 中使用超过 40% 的可以使用以下的方式进行，awk 也可以仅仅只做模式匹配。</p>
</blockquote>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">df -h <span class="p">|</span> awk <span class="s1">&#39;/^\/dev/ {print $(NF-1)&#34;---&#34;$0}&#39;</span> <span class="p">|</span> awk -F% <span class="s1">&#39;$1 &gt; 40&#39;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>（<strong>逻辑和比较符使用</strong>）例子 3：筛选/etc/passwd 中第三列=0 或者&gt;=1000 的用户名。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cat /etc/passwd <span class="p">|</span> awk -F: <span class="s1">&#39;$3==0 || $3&gt;=1000 {print $1}&#39;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这里也可以试一下算数运算符</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cat /etc/passwd <span class="p">|</span> awk -F: <span class="err">&#39;</span><span class="nv">$3</span><span class="o">==</span><span class="m">0</span> <span class="o">||</span> <span class="nv">$3</span>&gt;<span class="o">=</span><span class="m">1000</span> <span class="o">{</span>print <span class="nv">$1</span>,<span class="nv">$2</span>,<span class="nv">$3</span>+10086<span class="o">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="pattern-匹配格式">Pattern 匹配格式</h2>
<p>从上面的例子也可以知道模式匹配也是 awk 中重要的组成部分，下面介绍一下 awk 的匹配逻辑：</p>
<blockquote>
<p>根据 pattern 条件，过滤出匹配的行后再做后续的{action}处理，如果没有 action 就仅过滤</p>
</blockquote>
<p>主要有以下的几种模式：</p>
<ol>
<li><strong>None</strong>: 不写的话就匹配每一行</li>
<li><strong>/regular expression/</strong>：仅处理能被模式匹配到的行，<strong>正则</strong>需要被 <code>//</code> 包起来</li>
<li><strong>condition expression</strong>：awk 的条件表达式，结果为真的行才会被处理。</li>
<li><strong>line ranges</strong>：行范围
<ul>
<li>/pattern 1/, /pattern 2/ ：用两个 pattern 匹配到的行的范围，不支持直接给出数字，可以有多段，中间可以有间隔。</li>
</ul>
</li>
<li><strong>BEGIN/END</strong> 模式
<ul>
<li>BEGIN{}：仅在开始处理文件的文本之前执行一次</li>
<li>END{}：尽在文本处理完成之后执行</li>
</ul>
</li>
</ol>
<p>结合 BEGIN 和 END 等模式，就可以更好的格式化输出文件了，比如我们模拟 df -h 的标题行和新增总结行。我们提前备好一个没有对应的头的文件。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"> df -h <span class="p">|</span> awk -v <span class="nv">TOTAL</span><span class="o">=</span><span class="m">0</span> -v <span class="nv">USED</span><span class="o">=</span><span class="m">0</span> 
</span></span><span class="line"><span class="cl"> <span class="s1">&#39;BEGIN{printf &#34;%-10s\t%10s\t%10s\t%10s\t%10s\t%10s\n&#34;,&#34;FILESYSTERM&#34;,&#34;SIZE&#34;,&#34;USED&#34;,&#34;AVAIL&#34;,&#34;USE%&#34;,&#34;MONTED ON&#34;}
</span></span></span><span class="line"><span class="cl"><span class="s1">{TOTAL+=$2;USED+=$3;printf &#34;%-10s\t%10s\t%10s\t%10s\t%10s\t%10s\n&#34;,$1,$2,$3,$4,$5,$6}\
</span></span></span><span class="line"><span class="cl"><span class="s1"> END{printf &#34;%-10s\t%10s\t%10s\t%10s\t%10s\t%10s\n&#34;,&#34;SUM&#34;,TOTAL,USED,&#34;-&#34;,USED/TOTAL*100,&#34;WINDOWS&#34;}&#39;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以看到这里由 BEGIN、{}、END 三部分组成，结合 Printf 来实现文件的对齐。</p>
<h2 id="condition-条件语句">Condition 条件语句</h2>
<blockquote>
<p>介绍一下条件语句怎么编写。</p>
</blockquote>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="k">if</span> <span class="o">(</span>condition<span class="o">){</span>statement,...<span class="o">}</span><span class="k">else</span> <span class="k">if</span><span class="o">(</span>condition2<span class="o">){</span>statement2,...<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>statement<span class="o">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>举个例子，</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">df -h <span class="p">|</span> awk <span class="s1">&#39;{if ($1==&#34;none&#34;) print $1,$2,$3}&#39;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以看出，条件表达式是包在{ action }中的 action 的部分，其中 condition 要用 <code>()</code> 抱起来，然后后接 statement 即可。当然如果要 if、else 的话，statement 最好还是用 <code>{}</code> 包起来更好。</p>
<h2 id="loop-循环语句">Loop 循环语句</h2>
<blockquote>
<p>loop 的写法主要有三种，while；do-while；for；接下来主要简单介绍一下各个循环的写法。</p>
</blockquote>
<p>此外，控制循环的 continue 和 break 的用法和其他语言是一致的这里就不再说；这里再介绍一下对 awk 本身循环控制的一个指令：<code>next</code></p>
<p>awk 本身有个逐行处理的循环，next 会提前结束对本行的处理，进入对下一行的处理。</p>
<h3 id="while">While</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="k">while</span><span class="o">(</span>condition<span class="o">){</span>statement<span class="p">;</span>...<span class="o">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>使用场景</p>
<ul>
<li>对一行内的多个字段逐一类似处理时使用</li>
<li>对每一列的各元素逐一处理时使用</li>
</ul>
<p>举个例子：匹配以 None 开头的行，每一行输出每一列的值和长度。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">df -h <span class="p">|</span> awk <span class="s1">&#39;/^none/ {i=1;while(i&lt;NF){print $i, length($i); i++}}&#39;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="for">For</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="k">for</span> <span class="o">(</span>expr1<span class="p">;</span>expr2<span class="p">;</span>expr3<span class="o">)</span> <span class="o">{</span>statement<span class="p">;</span>...<span class="o">}</span>
</span></span><span class="line"><span class="cl">or
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="o">(</span>var in array<span class="o">){</span>statement<span class="p">;</span>...<span class="o">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以看出 for 循环和 cpp 的写法是一致的，两种就不在赘述了。</p>
<h3 id="do-while">do-while</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="k">do</span> <span class="o">{</span>statement<span class="p">;</span>...<span class="o">}</span> <span class="k">while</span><span class="o">(</span>condition<span class="o">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这里举个例子，计算 1+&hellip;..+100=5050</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">awk <span class="s1">&#39;BEGIN{sum=0;i=1;do{sum+=i;i++}while(i&lt;=100);print sum}&#39;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="additionswitch">（addition）switch</h3>
<p>这里额外介绍一下 switch 语句：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">switch<span class="o">(</span>expression<span class="o">)</span> <span class="o">{</span><span class="k">case</span> VALUE1 or /REGEXP/:statement1<span class="p">;</span> <span class="k">case</span> VALUE2 or /REGEXP2/: statement2<span class="p">;</span>...<span class="p">;</span> default: statementn<span class="o">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="自定义函数">自定义函数</h2>
<p>和bash区别：定义函数（）中需加参数，return返回值不是$?，是相当于echo输出</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="k">function</span> name <span class="o">(</span> parameter, parameter, ... <span class="o">)</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    statements
</span></span><span class="line"><span class="cl">    <span class="k">return</span> expression
</span></span><span class="line"><span class="cl"><span class="o">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>举例：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="k">function</span> max<span class="o">(</span>v1,v2<span class="o">)</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    v1&gt;v2?var<span class="o">=</span>v1:var<span class="o">=</span>v2
</span></span><span class="line"><span class="cl">    <span class="k">return</span> var
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">BEGIN<span class="o">{</span><span class="nv">a</span><span class="o">=</span>3<span class="p">;</span><span class="nv">b</span><span class="o">=</span>2<span class="p">;</span>print max<span class="o">(</span>a,b<span class="o">)}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="其他的一些函数介绍">其他的一些函数介绍</h2>
<ul>
<li>rand()生成 0-1 之间的随机数，需要首先 srand()初始化</li>
<li>length([s]) ：返回指定字符串的长度</li>
<li>sub(r,s,[t]) ：对t 字符串进行搜索r 表示的模式匹配的内容，并<strong>将第一个</strong>匹配的内容替换为s</li>
<li>gsub(r,s,[t]) ：对t 字符串进行搜索r 表示的模式匹配的内容，<strong>并全部替换</strong>为s 所表示的内容</li>
<li>plit(s,array,[r]) ：以 r 为分隔符，切割字符串 s ，并将切割后的结果保存至 array 所表示的数组中，第一个索引值为1, 第二个索引值为2,…</li>
</ul>
<h3 id="awk-中调用-shell-命令">awk 中调用 shell 命令</h3>
<p>使用 <code>system</code> 命令：</p>
<ul>
<li><code>awk BEGIN'{system(&quot;hostname&quot;) }'</code></li>
<li><code>awk 'BEGIN{name=&quot;along&quot;;system(&quot;echo &quot;name)}'</code></li>
</ul>
<h2 id="fi">Fi</h2>
<p>该篇还远不到结束，后续随着工作生活中用到再慢慢补充把，初步就到这里了，主要还是参考的网上的文献，实践还是太少了。</p>
]]></content:encoded>
    </item>
    <item>
      <title>Grep、Sed、Awk 02 Sed</title>
      <link>https://aikenh.cn/posts/linux%E4%B8%89%E5%89%91%E5%AE%A2%E4%B9%8Bsed/</link>
      <pubDate>Sat, 15 Apr 2023 23:22:56 +0000</pubDate>
      <guid>https://aikenh.cn/posts/linux%E4%B8%89%E5%89%91%E5%AE%A2%E4%B9%8Bsed/</guid>
      <description>Linux 三剑客之Sed</description>
      <content:encoded><![CDATA[<blockquote>
<p>Linux 三剑客之 Sed，相比于擅长数据查找定位的 Grep，Sed（Stream Editor）擅长做的是数据修改，做的主要是做一些增删改的功能。<a href="https://www.zhihu.com/question/297858714" target="_blank" rel="noopener"> sed 和 awk 的区别是什么？</a>
</p>
</blockquote>
<h2 id="intro">Intro</h2>
<p>首先介绍 Sed 命令，Stream Editor 流编辑器，针对字符流来进行文件编辑，同样，其核心也在于正则匹配式，其用法如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sed <span class="o">[</span>option<span class="o">]</span> <span class="o">{</span>script<span class="o">}</span> <span class="o">[</span>input-file<span class="o">]</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>其中{script}可以理解为三者的组合：<strong>sed 动作指令+Reg 用正则&amp;行号确定修改位置+修改的内容</strong>：Script 是 Sed 的核心，分别对应着：操作的行为，操作的位置和操作的内容。</p>
<p>Sed 的用法也可以按照这个来记：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sed <span class="o">[</span>-hnV<span class="o">]</span> <span class="o">[</span>-e &lt;script&gt;<span class="o">]</span> <span class="o">[</span>-f &lt;script文件&gt;<span class="o">]</span> <span class="o">[</span>文本文件<span class="o">]</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><blockquote>
<p>h 显示 helo ；-n 表示静默输出，-V 显示版本；参考第一种用法，-e 可以指定多个 script 对输入的文件进行处理，-f 则可以将多个 script 写在文件中，通过读取文件中的 scripts 来对文本文件进行处理。</p>
</blockquote>
<p>作为文本<strong>流</strong>编辑器，Sed 是一行一行的处理文件内容，将正在处理的每一行内容放在缓冲区中按照约定进行修改，处理后按照约定修改文件或输出，接着在处理下一行，直到整个文件处理内容。</p>
<p>其主要用来编辑和处理一个或者多个文件，简化对于文件的重复操作。</p>
<p>参考资料：<a href="https://www.zhihu.com/question/297858714" target="_blank" rel="noopener">sed 和 awk 的区别-知乎</a>
 | Man | <a href="https://coolshell.cn/articles/9104.html" target="_blank" rel="noopener">sed 简明教程 | CoolShell</a>
 | <a href="https://www.runoob.com/linux/linux-comm-sed.html" target="_blank" rel="noopener">Linux sed 命令 | 菜鸟教程 </a>
 |  <a href="https://www.cnblogs.com/along21/p/10366886.html" target="_blank" rel="noopener">Linux文本三剑客超详细教程&mdash;grep、sed、awk </a>
</p>
<h2 id="options-常用选项">Options 常用选项</h2>
<ul>
<li><strong>-e</strong> 多点编辑，对每行处理时使用多个 Script</li>
<li><strong>-f</strong> 将 scrips 写到文件里，如果是多个 script 之间换行</li>
<li><strong>-r/E</strong> 支持拓展的正则表达式</li>
<li><strong>-i</strong> 直接将修改写入文件（如果不加入 i 的话不会修改文件，只会讲修改过后的内容进行输出，后续也可以使用重定向输入到文件中）</li>
<li><strong>-i.bak</strong> 直接将修改写入文件，但是会将原本的文件备份到*.bak</li>
<li><strong>-n</strong> 静默输出。</li>
</ul>
<h2 id="scripts-编辑命令编写">Scripts 编辑命令编写</h2>
<p>上述提到，Sed 的核心在于 Script，其编写主要由三个部分组成，Command（行为） + Located（定界，确定修改的位置）+ Content（修改内容，增或者改的时候需要，删无需）这里主要介绍以下常用的动作指令和定界方式。</p>
<h3 id="command-动作指令">Command 动作指令</h3>
<p>具体的所有动作指令还是要参考 Man 文档，这里只介绍一些常用的 command，</p>
<table>
  <thead>
      <tr>
          <th>Command</th>
          <th>Type</th>
          <th>Desc</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>a</td>
          <td>增</td>
          <td>Append 后接字符，在指定行的下一行添加指定的新的字符，支持 <code>\n</code></td>
      </tr>
      <tr>
          <td>i</td>
          <td>增</td>
          <td>Insert 后接字符，在指定行的上一行添加指定的新的字符，支持 <code>\n</code></td>
      </tr>
      <tr>
          <td>d</td>
          <td>删</td>
          <td>删除通常不接任何字符，删除当前行</td>
      </tr>
      <tr>
          <td>c</td>
          <td>改</td>
          <td>change 可接字符串，可以取代 n1，n 2 之间的行，支持 <code>\n</code></td>
      </tr>
      <tr>
          <td>s ///</td>
          <td>改</td>
          <td>查找与替换，通常搭配正则表达式使用，将指定的词替换成新词</td>
      </tr>
      <tr>
          <td>p</td>
          <td>输出</td>
          <td>Print，将某个指定的数据输出，通常会配合-n 一起用</td>
      </tr>
      <tr>
          <td>=</td>
          <td>输出</td>
          <td>为模式匹配空间的行打印行号</td>
      </tr>
      <tr>
          <td>w</td>
          <td>输出</td>
          <td>保存模式匹配空间的行到指定文件</td>
      </tr>
      <tr>
          <td>！</td>
          <td>功能</td>
          <td>模式空间中匹配行取反处理</td>
      </tr>
  </tbody>
</table>
<p>其中 <strong>s 替换</strong>命令，在诸多动作指令中算是一个非常常见的命令，其用法略为复杂一些，这里做基础介绍：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">s /&lt;before&gt;/&lt;after&gt;/&lt;type&gt;</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这里的 before 和 after 都好理解，type 为 <code>g</code> 表示对匹配到的行内进行全局替换，为任意 <code>num </code> 的时候则是匹配每一行中第几个匹配到的值，<code>num+g </code> 的话就代表从 num 个起。</p>
<p>这里介绍一个替换的例子，假如我们希望删除 html 中的 tags</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">b</span><span class="p">&gt;</span>This<span class="p">&lt;/</span><span class="nt">b</span><span class="p">&gt;</span> is what <span class="p">&lt;</span><span class="nt">span</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;text-decoration: underline;&#34;</span><span class="p">&gt;</span>I<span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span> meant. Understand?</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>若使用以下的指令，会将<code>&lt;b</code> 和 <code>span&gt;</code>中的内容全部删除，并非理想的效果。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sed <span class="s1">&#39;s/&lt;.*&gt;//g&#39;</span> html.txt</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>我们需要借助正则的方式来避免这种情况，如下除了&gt;的字符重复 0 次或多次即可；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sed <span class="s1">&#39;s/&lt;[^&gt;]*&gt;//g&#39;</span> html.txt</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="located-地址定界">Located 地址定界</h3>
<p>sed 会使用到的&quot;定界&quot;方式实际上主要有两种：</p>
<ul>
<li>匹配：使用正则表达式进行匹配</li>
<li>地址范围：指定行</li>
</ul>
<p>但是其中匹配的方式，可以按照模式能够匹配到的每一行进行理解，这样的话就可以整理成以下的几种方式；</p>
<ul>
<li>
<p><strong>不给地址</strong>：对全文进行处理</p>
</li>
<li>
<p><strong>指定地址</strong>：</p>
<ul>
<li><code>n</code> 即指定的第 n 行</li>
<li><code>/pattern/</code> 即被此处模式能匹配到的每一行</li>
</ul>
</li>
<li>
<p><strong>地址范围</strong>有以下的表示方式</p>
<ul>
<li><code>n1,n2</code> 表示处理 n1 到 n2 的范围，</li>
<li><code>n1,+n</code> 表示处理 n 1 到 $n 1+n$ 的范围</li>
<li><code>/pat1/，/pat2/</code> 表示从 pattern1 到 pattern2 的范围，但是注意会匹配每一个这样的组，如果某个 patern1 没有被 pattern2 闭起来的话就会输出到末尾。</li>
<li><code>n,/pat1</code> 表示从 n 行到 pattern1 的范围</li>
<li><code>/pat1/,+n</code> 则表示从 pattern 1 即之后的 n 行</li>
<li>类似这种方式可以对这几种行匹配方式进行自由组合</li>
</ul>
</li>
<li>
<p><strong>步进表达式</strong>，通常用以表示单双行</p>
<ul>
<li><code>sed -n '1~2p'</code> 表示只打印奇数行，从第一行开始，搁两行输出</li>
<li><code>sed -n '2~2p'</code> 表示只打印偶数行</li>
</ul>
</li>
</ul>
<p>需要注意，sed 定义的行号是从第 1行开始的，没有第 0 行；此外，进行测试的时候输入-n 能够防止输出未匹配到的行从而混淆视听，这里可以使用如下的命令，结合-n 和 p command 来做测试。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sed -n <span class="s1">&#39;&lt;locate&gt;p&#39;</span> &lt;file&gt;</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="usage-用法展示">Usage 用法展示</h2>
<p>这里会零零散散的展示一些没那么常规或者值得一提的用法，具体的类型会通过 title 指出；还有一些什么单双行匹配的使用特定的定界符号 <code>1~2</code> 在地址的前面就行，</p>
<h3 id="type-1--在行末或行前添加">Type 1  在行末或行前添加</h3>
<p>如果需要在每行末尾或行首添加指定内容（非换行的情况），则不能使用 <code>a</code> 或者 <code>i</code> 命令，需要使用 <code>s</code> 结合正则的方式实现：</p>
<p>例如给 ip 地址添加端口 <code>：22</code>，原文件如下</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">192.168.0.1
</span></span><span class="line"><span class="cl">192.168.0.2</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>则使用 <code>^</code> 代表行首，<code>$</code> 代表行尾，使用如下的命令进行修改</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sed <span class="s2">&#34;1,2s/</span>$<span class="s2">/:22/g&#34;</span> ip_file <span class="c1">#末尾添加,但是只处理1-2行</span>
</span></span><span class="line"><span class="cl">sed <span class="s2">&#34;s/^/ip:/g&#34;</span> ip_file <span class="c1">#头部添加</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>拓展：当源文件如下，我们只需要添加缺失的时候，同样可以使用正则表达式进行处理。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">192.168.0.1
</span></span><span class="line"><span class="cl">192.168.0.2:80</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>使用正则定界并取反，排除存在:port 的行，对剩下的行进行替换</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sed <span class="s2">&#34;/:[0-9]*</span>$<span class="s2">/ ! s/</span>$<span class="s2">/:22/g&#34;</span> ip_file </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>参考资料：<a href="https://stackoverflow.com/questions/15978504/add-text-at-the-end-of-each-line" target="_blank" rel="noopener">sed - Add text at the end of each line - Stack Overflow</a>
</p>
<h3 id="type-2-多-script-匹配">Type 2 多 Script 匹配</h3>
<p>还是上面的例子，如果我们希望同时在头部和尾部添加东西（或者类似的多个匹配操作），可以用以下方式来同时执行多个匹配模式。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sed -e <span class="s2">&#34;/:[0-9]*</span>$<span class="s2">/ ! s/</span>$<span class="s2">/:22/g&#34;</span> -e <span class="s2">&#34;s/^/ip:&#34;</span> ip_file</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>就可以同时执行头部和尾部的内容添加，同样也可以按照以下的方式写：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sed -e <span class="s2">&#34;/:[0-9]*</span>$<span class="s2">/ ! s/</span>$<span class="s2">/:22/g; s/^/ip:&#34;</span> ip_file</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>还可以使用 <code>-f</code> 参数将多个 script 写在文件中</p>
<h3 id="type-3-多-script-组合">Type 3 多 Script 组合</h3>
<p>当处理的是不同地方的多个脚本，可以使用多 script 匹配的方式进行，但是当我们针对一个匹配字符进行多个处理的时候，可以使用 <code>{}</code> 来组合 <code>command</code> ，每个命令之间用 <code>;</code> 分割。</p>
<p>比如我们希望将 192 修改成 172 后输出：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sed -n <span class="s2">&#34;/192/{s/192/172/g;p}&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>上面这个命令首先找到 192 匹配的行，然后针对改行执行替换后，执行输出指令；</p>
<h3 id="type-4-将匹配值作变量">Type 4 将匹配值作变量</h3>
<p>可以用 <code>&amp;</code> 代表被匹配到的变量，然后就可以基于该变量进行修改，比如我们识别到 192 开头的就在其前面加上 LAN_ADDR:</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sed <span class="s2">&#34;s/192/LAN_ADDR:&amp;/g&#34;</span> ip_file</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>当然这里也可以直接用 192 表示，但是如果我们的 192 只是一个用通配符匹配到的模式的时候就能发挥其作用。</p>
<blockquote>
<p>可以用来做大小写转换</p>
</blockquote>
<p>同样，根据该命令我们也可以进行特定字符的<strong>大小写转换</strong>，首先给出部分特殊参照符号如下，结合以下的参数就可以实现大小写转换。</p>
<table>
  <thead>
      <tr>
          <th>symbol</th>
          <th>function</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>\u</code></td>
          <td>将下一个字符转变成大写</td>
      </tr>
      <tr>
          <td><code>\l</code></td>
          <td>将下一个字符转变为小写</td>
      </tr>
      <tr>
          <td><code>\U</code></td>
          <td>将 replacement 的字符转变为大写，直到 <code>\U 或 \E</code> 出现</td>
      </tr>
      <tr>
          <td><code>\L</code></td>
          <td>将 replacement 的字符转变为大写，直到 <code>\L 或 \E</code> 出现</td>
      </tr>
      <tr>
          <td><code>\E</code></td>
          <td>停止大小写转换</td>
      </tr>
  </tbody>
</table>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sed <span class="s2">&#34;s/[a-z]/\u&amp;/g&#34;</span> ip_file</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这样就可以将全文的英文字符做大小写转换了，可以以类似方式对指定的字符进行转换。</p>
<blockquote>
<p>圆括号匹配也是一种将匹配值作为变量的方式</p>
</blockquote>
<p><strong>圆括号匹配</strong>: 使用圆括号括起来的正则表达式所匹配的字符串可以当成变量来使用，sed 中使用 <code>\1</code> ; <code>\2</code> &hellip;来引用对应的匹配值。</p>
<p>参考自<a href="https://coolshell.cn/articles/9104.html#Pattern_Space" target="_blank" rel="noopener">sed 简明教程 CoolShell</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sed <span class="s2">&#34;s/\([^.]*\).1\([^1]*\).1/\1:\2/g&#34;</span> ipfile</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>其中 <code>\1</code> 代表 <code>\([^.]*\) </code> 匹配到的内容也就是 192，<code>\2</code> 则是代表 <code>\([^1]*\)</code> 匹配到的内容是 68.0，该行命令会将 192.168.0.1 转换成 1 92:68 .0</p>
<p><strong>注意</strong>使用圆括号匹配的时候需要使用 <code>\</code> 转义符，不然会当成普通的括号或者报错。</p>
<h3 id="type-5-管道处理">Type 5 管道处理</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cat log_file <span class="p">|</span> sed <span class="s2">&#34;s/bef/aft&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="advanced-高级用法">Advanced 高级用法</h2>
<p>该部分摘自参考资料：<a href="https://www.cnblogs.com/along21/p/10366886.html" target="_blank" rel="noopener">Linux文本三剑客超详细教程&mdash;grep、sed、awk </a>
</p>
<h3 id="manual-格式手册">Manual 格式手册</h3>
<p>进阶命令格式（用的时候再来查表吧），通过 Hold Space 相当于可以引入一个中间变量来做一些单变量无法实现的处理，比如说将文章倒序输出；</p>
<ul>
<li> h：把模式空间中的内容覆盖至保持空间中</li>
<li> H：把模式空间中的内容追加至保持空间中</li>
<li> g：从保持空间取出数据覆盖至模式空间</li>
<li> G：从保持空间取出内容追加至模式空间</li>
<li> x：把模式空间中的内容与保持空间中的内容进行互换</li>
<li> n：读取匹配到的行的下一行覆盖 至模式空间</li>
<li> N：读取匹配到的行的下一行追加 至模式空间</li>
<li> d：删除模式空间中的行</li>
<li> D：删除 当前模式空间开端至\n 的内容（不再传 至标准输出），放弃之后的命令，但是对剩余模式空间重新执行sed</li>
</ul>
<h3 id="reverse-倒序显示文件">Reverse 倒序显示文件</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sed <span class="s1">&#39;1!G;h;$!d&#39;</span> num.txt</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>该命令能将文本倒序输出，具体的原理如下：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230418150137.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230418150137.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230418150137.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>该 Hold Space 还能用于什么情况我们后续补充，文中的其他例子好像不需借助 Hold Space 就可以实现了。</p>
<h2 id="extra-info-其他设置">Extra Info 其他设置</h2>
<h3 id="delimiter-分隔符选择">Delimiter 分隔符选择</h3>
<p>实际上在 sed 中，除了使用 <code>/</code> 还可以使用 <code>@</code> ,  <code>|</code> , <code>!</code> , ` 四种分隔符，其中比较推荐的还是 <code>|</code>,其他的几个分隔符和原本的 <code>/</code> 在可读性上没有优势。<code>/</code> 主要是涉及到转义符号的时候有些头皮发麻。</p>
<p>参考资料： <a href="https://www.twle.cn/c/yufei/sed/sed-basic-strings-delimiter.html" target="_blank" rel="noopener">sed 模式分隔符 - sed 基础教程 </a>
</p>
<h3 id="special-symbol-特殊符号">Special Symbol 特殊符号</h3>
<p>添加制表符直接使用 <code>\t</code> 是无效的无法正确识别 Tab，原本说 <code>sed</code> <a href="https://cloud.tencent.com/developer/ask/sof/115798" target="_blank" rel="noopener">不支持</a>
 <code>\n</code> 和 <code>\t</code> 但是实际测试<a href="https://blog.csdn.net/woyaoyonghanzizhuce/article/details/102614041" target="_blank" rel="noopener">以下的方式</a>
是可以添加两种字符的。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># create the origin file</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;hello world&#34;</span> &gt;&gt; test_file
</span></span><span class="line"><span class="cl">sed -i <span class="s2">&#34;1a\ \tThis slash spc and slash t will add tab&#34;</span> test_file
</span></span><span class="line"><span class="cl">sed -i <span class="s2">&#34;1a\ \nThis way can generate n also&#34;</span> test_file</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="mac-上的特殊处理">Mac 上的特殊处理</h3>
<blockquote>
<p>需要注意的是 Sed 命令在 Linux 和 Macos 上存在较大的不同，在 Linux 中的功能更全面一些，这是由于 MacOs 是基于 BSD 的存在一些不足，可以通过 homebrew 下载额外的 sed</p>
</blockquote>
<ul>
<li>sed -i 在 mac 中需要指定用于备份的后缀，也可以用 <code>&quot;&quot;</code> 取消备份，否则会报错 <code>invalid command code</code></li>
<li>sed -i 在 mac 中输入需要添加的行的时候，需要需要换行</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sed -i <span class="s2">&#34;&#34;</span> -e <span class="s2">&#34;</span><span class="si">${</span><span class="nv">line_num</span><span class="si">}</span><span class="s2"> a\\
</span></span></span><span class="line"><span class="cl"><span class="s2">plugins=\(
</span></span></span><span class="line"><span class="cl"><span class="s2">&#34;</span> test.sh</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script>]]></content:encoded>
    </item>
    <item>
      <title>Grep、Sed、Awk 01-Grep</title>
      <link>https://aikenh.cn/posts/linux%E4%B8%89%E5%89%91%E5%AE%A2%E4%B9%8Bgrep/</link>
      <pubDate>Wed, 12 Apr 2023 13:22:58 +0000</pubDate>
      <guid>https://aikenh.cn/posts/linux%E4%B8%89%E5%89%91%E5%AE%A2%E4%B9%8Bgrep/</guid>
      <description>Linux三剑客之Grep</description>
      <content:encoded><![CDATA[<blockquote>
<p>Linux 三剑客之 Grep。Grep 估计会是大部分 Linux 用户最常用的文本搜索命令了，在三剑客中的使用场景也是最广泛的。在对正则有了基本了解之后，就可以更好的使用 Grep，同时也可以通过 Grep 的使用来更好的掌握常用的正则表达式。</p>
</blockquote>
<h2 id="intro">Intro</h2>
<p>首先介绍 Grep 命令，<strong>Global Regular Expression Print</strong> 全局正则表达式输出，使用正则表达式搜索文本内容输出。其使用模板如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">grep <span class="o">[</span>option<span class="o">]</span> pattern file</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>option 指定 grep 的搜索模式</li>
<li>pattern 需要搜索的内容，可以用<strong>正则表达式</strong>指定一个模式来做匹配</li>
<li>file 可以是文件夹等路径，用来确定搜索的范围（仅支持<strong>通配符</strong>）[[Published发布/Linux三剑客之正则]]</li>
</ul>
<p>接下来分别对两个部分进行简单的说明，file 的范围指定参考正则文章中对通配符的介绍即可。</p>
<h2 id="option-搜索模式">Option 搜索模式</h2>
<p>参考资料：<a href="https://manpages.debian.org/unstable/manpages-zh/index.html" target="_blank" rel="noopener"><code>man grep</code></a>
，<a href="https://manpages.debian.org/unstable/manpages-zh/grep.1.zh_CN.html" target="_blank" rel="noopener">ManPage-zh</a>
 具体完整的有哪些搜索模式可以在 man page 中进行查看。这里主要介绍一些常见的搜索模式和一些使用场景。</p>
<center> option 对照表 </center>
<table>
  <thead>
      <tr>
          <th>Key Word</th>
          <th>Function</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>-w</td>
          <td>全词匹配</td>
      </tr>
      <tr>
          <td>-i</td>
          <td>忽略大小写</td>
      </tr>
      <tr>
          <td>-I</td>
          <td>搜索时忽略二进制文件</td>
      </tr>
      <tr>
          <td>-r</td>
          <td>搜索时递归搜索文件夹里的内容</td>
      </tr>
      <tr>
          <td>-l</td>
          <td>仅输出搜寻到匹配的文件名</td>
      </tr>
      <tr>
          <td>-c</td>
          <td>仅输出每一个输入文件中的匹配次数(v 结合的话就是不匹配的次数)</td>
      </tr>
      <tr>
          <td>-n</td>
          <td>显示行号</td>
      </tr>
      <tr>
          <td>-o</td>
          <td>仅输出每行中的匹配内容</td>
      </tr>
      <tr>
          <td>-v</td>
          <td>反向搜索，搜索不匹配该模式的行</td>
      </tr>
      <tr>
          <td>-A num</td>
          <td>同时打印出匹配行的下 num 行</td>
      </tr>
      <tr>
          <td>-B num</td>
          <td>同时打印出匹配行的上 num 行</td>
      </tr>
      <tr>
          <td>-C num</td>
          <td>同时打印出匹配行的前后 num 行</td>
      </tr>
      <tr>
          <td>-E</td>
          <td>将模式按照拓展正则来读取</td>
      </tr>
      <tr>
          <td>-q</td>
          <td>取消输出，在匹配到时输出非 0 值，未匹配时返回 0，用于条件判断</td>
      </tr>
      <tr>
          <td>-f</td>
          <td>指定 Pattern 文件，每行一个 patten，匹配到其中一个即可（-F 会视为固定的字符串）</td>
      </tr>
      <tr>
          <td>-x</td>
          <td>仅显示整行匹配的</td>
      </tr>
  </tbody>
</table>
<h2 id="pattern-匹配模式">Pattern 匹配模式</h2>
<p>正则匹配的部分这里就不在赘述，参考前文的正则表达式部分。（用 Grep 来熟悉正则也是一个不错的选择）</p>
<p>下面会结合使用方式来介绍一些例子。参考资料：<a href="https://wangchujiang.com/linux-command/c/grep.html" target="_blank" rel="noopener">grep 命令，Linux grep 命令详解：强大的文本搜索工具 </a>
</p>
<h2 id="usage-使用方式">Usage 使用方式</h2>
<h3 id="type-1-在文件夹中搜索单词">Type 1 在文件(夹)中搜索单词</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">grep match_pattern file_name
</span></span><span class="line"><span class="cl">grep -r match_pattern *</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果不指定 file_name 或者目录会在默认目录中搜索，所以启用-r 的时候记得要指定目录。同时通常搜索的时候，我们也希望能够知道匹配文本的位置；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">grep -rniI match_pattern * --color<span class="o">=</span>auto</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这里 r 用于搜索目录，n 输出行数，i 忽略大小写，I 忽略二进制文件，color 指定输出带颜色，便于观看，但是对新的 shell 来说，通常已经将 color 参数写入了 grep 的 alias，可以在命令行中查看。</p>
<h3 id="type-2-在多个文件中查找">Type 2 在多个文件中查找</h3>
<p>不同于在目录中搜索，如果要指定特定的多个文件，可以按照以下的方式来：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">grep -w <span class="s2">&#34;key_word&#34;</span> file_1 file_2 file_3 ...</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>上面的命令希望在 file1~3 中搜索完全匹配 key_word 的行</p>
<h3 id="type-3-管道搜索">Type 3 管道搜索</h3>
<p>当我们需要对一些指令的输出内容中进行搜索的时候，就会用到这种方式，比如：</p>
<ol>
<li>编译或运行过程中的 Log 筛选出 Fatal</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sh makr_run.sh <span class="p">|</span> grep FATAL &gt;&gt; FATAL.log</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="2">
<li>查看特定的历史指令</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">history</span> -i <span class="p">|</span> grep git</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="type-4--用作条件判断">Type 4  用作条件判断</h3>
<p>其实该部分主要是使用静默输出参数，该参数主要在 shell 脚本中用作条件测试。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cat <span class="nv">$file</span> <span class="p">|</span> grep model <span class="p">|</span> grep -q resnet
</span></span><span class="line"><span class="cl"><span class="c1"># is_model=$? </span>
</span></span><span class="line"><span class="cl"><span class="c1"># $? 返回上一条命令的执行结果，0表示成功，其他表示失败</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="type-5-与或非">Type 5 与或非</h3>
<p>与可以利用管道连接符进行多次匹配即可，非则是-v</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">grep -in key1 file <span class="p">|</span> grep key2</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>或有以下的几种方式</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">grep <span class="s1">&#39;key1\|key2&#39;</span> filename
</span></span><span class="line"><span class="cl">grep -E <span class="s1">&#39;pattern1|pattern2&#39;</span> filename</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>或者使用-e 来制动多个匹配模式</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;model=tcnn&#34;</span> <span class="p">|</span> grep -e <span class="s2">&#34;resnet&#34;</span> -e <span class="s2">&#34;tcnn&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="type-6--包含或排除指定文件">Type 6  包含或排除指定文件</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 只在目录中所有的.php和.html文件中递归搜索字符&#34;main()&#34; </span>
</span></span><span class="line"><span class="cl">grep <span class="s2">&#34;main()&#34;</span> . -r --include *.<span class="o">{</span>php,html<span class="o">}</span> 
</span></span><span class="line"><span class="cl"><span class="c1"># 在搜索结果中排除所有README文件 </span>
</span></span><span class="line"><span class="cl">grep <span class="s2">&#34;main()&#34;</span> . -r --exclude <span class="s2">&#34;README&#34;</span> 
</span></span><span class="line"><span class="cl"><span class="c1"># 在搜索结果中排除filelist文件列表里的文件 </span>
</span></span><span class="line"><span class="cl">grep <span class="s2">&#34;main()&#34;</span> . -r --exclude-from filelist</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script>]]></content:encoded>
    </item>
    <item>
      <title>Grep、Sed、Awk 00 RegExp</title>
      <link>https://aikenh.cn/posts/linux%E4%B8%89%E5%89%91%E5%AE%A2%E4%B9%8B%E6%AD%A3%E5%88%99/</link>
      <pubDate>Tue, 11 Apr 2023 22:57:40 +0000</pubDate>
      <guid>https://aikenh.cn/posts/linux%E4%B8%89%E5%89%91%E5%AE%A2%E4%B9%8B%E6%AD%A3%E5%88%99/</guid>
      <description>Linux 三剑客之RegExp</description>
      <content:encoded><![CDATA[<blockquote>
<p>“awk、grep、sed 是 linux 操作文本的三大利器，合称文本三剑客，也是必须掌握的 linux 命令之一。三者的功能都是处理文本，但侧重点各不相同，其中属 awk 功能最强大，但也最复杂。grep 更适合单纯的查找或匹配文本，sed 更适合编辑匹配到的文本，awk 更适合格式化文本，对文本进行较复杂格式处理。“</p>
</blockquote>
<p><a href="https://www.cnblogs.com/along21/p/10366886.html" target="_blank" rel="noopener">Linux文本三剑客超详细教程&mdash;grep、sed、awk</a>
</p>
<p>在介绍这三个命令之前，需要对正则表达式有所了解，结合正则表达式来使用，才能发挥这 linux 三剑客的的全部能力。</p>
<h2 id="正则表达式-regexp">正则表达式 RegExp</h2>
<p>正则表达式： Regual Expression 为一类特殊字符和文本符号共通约定的一种 pattern，其中的一些字符并不表示其本身的含义，而是用来做通配符号。</p>
<p>其中基本正则表达式 BRE 是普遍支持的，而拓展正则表达式 ERE 通常则是需要特殊的参数来启用的。通过正则表达式中特殊符号的辅助，能够更快的过滤，查找，替换，处理字符流等。</p>
<p>除了在 grep、sed、awk 的 linux 三剑客中，在各个语言和各种搜索函数的地方，正则表达式都被普遍支持，应用相当广泛。</p>
<p>基础正则表达式对应的元字符主要有以下几个：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">^ $ . <span class="o">[</span> <span class="o">]</span> *</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>而拓展正则表达式在上述元字符的基础上增加了：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="o">(</span> <span class="o">)</span> <span class="o">{</span> <span class="o">}</span> ? + <span class="p">|</span> </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>等字符，接下来我们将逐一展开各个元字符的作用。</p>
<h3 id="基础正则表达式-bre">基础正则表达式 BRE</h3>
<p>正则表达式的元字符会起到以下的三个作用，从而定义某种特殊的字符模式：</p>
<ul>
<li>匹配字符（<code>.</code>  <code>[anychar]</code>, <code>\</code>）</li>
<li>匹配次数（<code>*</code>）</li>
<li>位置锚定（<code>^</code>, <code>$</code>）</li>
</ul>
<p>粗略的可以划分为以上的三类，而详细的作用则如同下表所示。</p>
<table>
  <thead>
      <tr>
          <th>字符</th>
          <th>作用</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>^</code></td>
          <td>写在 Pattern 的开头，如 <code>^header</code>，匹配以 header 开头的行</td>
      </tr>
      <tr>
          <td><code> $</code></td>
          <td>写在 Pattern 的结尾，如 <code>tail$ </code>，将匹配以 tail 结尾的行</td>
      </tr>
      <tr>
          <td><code>^$</code></td>
          <td>组合符，表示空行</td>
      </tr>
      <tr>
          <td><code>\</code></td>
          <td>转义符，让特殊的这些元字符不做元字符，而作为普通字符来进行匹配</td>
      </tr>
      <tr>
          <td><code>.</code></td>
          <td>匹配任意一个字符（非空行）一次</td>
      </tr>
      <tr>
          <td><code>*</code></td>
          <td>匹配前一个字符（连续出现）0 次到无穷次</td>
      </tr>
      <tr>
          <td><code>.*</code></td>
          <td>组合符，将匹配一切</td>
      </tr>
      <tr>
          <td><code>^.*</code></td>
          <td>组合符，匹配以任意字符串开头的内容</td>
      </tr>
      <tr>
          <td><code>.*$</code></td>
          <td>组合符，匹配以任意字符串结尾的内容</td>
      </tr>
      <tr>
          <td><code>[abc]</code></td>
          <td>匹配 <code>[]</code> 集合中的任意字符，a 或 b 或 c，可以写成 <code>[a-c]</code></td>
      </tr>
      <tr>
          <td><code>[^abc]</code></td>
          <td>上述匹配的反向，匹配除了 <code>[]</code> 集合中的任意字符，^表示取反</td>
      </tr>
  </tbody>
</table>
<p>此外还有如下的两种正则：</p>
<ul>
<li><code>\&lt;</code> 表示词首。如：<code>\&lt;abc</code> 表示以 abc 为首的词。</li>
<li><code>\&gt;</code> 表示词尾。如：<code>abc\&gt;</code> 表示以 abc 结尾的词。</li>
</ul>
<h3 id="拓展正则表达式-ere">拓展正则表达式 ERE</h3>
<p>拓展表达式拓展了上述三个字符模式的元组，拓展字符支持的如下：</p>
<ul>
<li>匹配字符：<code>|</code>，<code>()</code></li>
<li>匹配次数：<code>+</code>，<code>？</code>，<code>{n, m}</code></li>
<li>位置锚定：</li>
</ul>
<table>
  <thead>
      <tr>
          <th>字符</th>
          <th>作用</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>+</code></td>
          <td>匹配<strong>前一个字符</strong>（连续出现）1 次到无穷次</td>
      </tr>
      <tr>
          <td><code>[ab]+</code></td>
          <td>组合符，匹配 <code>[]</code> 中的 a/b 一次到 N 次</td>
      </tr>
      <tr>
          <td><code>?</code></td>
          <td>匹配<strong>前一个字符</strong>（连续出现）0 次到 1 次</td>
      </tr>
      <tr>
          <td><code>|</code></td>
          <td>或者，表示同时过滤多个字符串</td>
      </tr>
      <tr>
          <td><code>()</code></td>
          <td>分组过滤，括号起来的内容表示一个整体</td>
      </tr>
      <tr>
          <td><code>{n,m}</code></td>
          <td>匹配<strong>前一个字符</strong> n 到 m 次，<code>n,</code> 表示&gt;=n, <code>,m</code> 表示&lt;=m, <code>n</code> 表示正好为n</td>
      </tr>
  </tbody>
</table>
<blockquote>
<p>其中表示或者的是|，由于表格的原因显示有问题。</p>
</blockquote>
<h3 id="特殊符号表">特殊符号表</h3>
<p>下面这些特殊匹配的字符，需要用的时候查表即可。</p>
<table>
  <thead>
      <tr>
          <th>符号</th>
          <th>匹配字符</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>[:alnum:]</code></td>
          <td>同 <code>[0-9a-zA-Z]</code> 匹配数字和字母</td>
      </tr>
      <tr>
          <td><code>[:alpha:]</code></td>
          <td>同 <code>[a-zA-Z]</code> 匹配大小写字母</td>
      </tr>
      <tr>
          <td><code>[:upper:]</code> / <code>[:lower:]</code></td>
          <td>同 <code>[A-Z]</code> / <code>[a-z]</code> 匹配大/小写字母</td>
      </tr>
      <tr>
          <td><code>[:blank:]</code></td>
          <td>空白字符，空格和制表符</td>
      </tr>
      <tr>
          <td><code>[:space:]</code></td>
          <td>水平和垂直的空白字符，比 blank 的范围更广</td>
      </tr>
      <tr>
          <td><code>[:cntrl:]</code></td>
          <td>不可打印的控制字符（退格，删除，警铃）</td>
      </tr>
      <tr>
          <td><code>[:digit:]</code></td>
          <td>十进制数字或 <code>[0-9]</code></td>
      </tr>
      <tr>
          <td><code>[:xdigit:]</code></td>
          <td>十六进制数字</td>
      </tr>
      <tr>
          <td><code>[:graph:]</code></td>
          <td>可打印的非空白字符</td>
      </tr>
      <tr>
          <td><code>[:print:]</code></td>
          <td>可打印字符</td>
      </tr>
      <tr>
          <td><code>[:punct:]</code></td>
          <td>标点符号</td>
      </tr>
  </tbody>
</table>
<p>需要注意的是，使用 zsh 的时候，这些特殊字符可能会出现 <code>zsh no matches found</code> 的错误，这是因为 zsh 把这些特殊符号当成了命令行的参数，而不是 grep 的参数，因此导致失效。</p>
<p>为此可以在 zshrc 中添加以下命令，使其兼容 bash 的模式。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>rc</span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code class="language-rc" data-lang="rc">setopt no_nomatch</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>参考资料：<a href="https://blog.csdn.net/duke_ding2/article/details/123909360" target="_blank" rel="noopener"> zsh下报错“zsh: no matches found:” CSDN</a>
</p>
<h2 id="用法补充">用法补充</h2>
<h3 id="分组机制详解">分组机制详解</h3>
<p>待补充</p>
<h2 id="正则表达式与通配符">正则表达式与通配符</h2>
<p>参考资料：<a href="https://abcfy2.gitbooks.io/linux_basic/content/first_sense_for_linux/command_learning/wildcard.html" target="_blank" rel="noopener">通配符 | Linux基础概要 (gitbooks.io)</a>
</p>
<p>通配符用于通配文件名，正则表达式用于匹配文本内容；且通配符通常只能用于 shell，被 shell 自解释，正则表达式则需要正则引擎进行处理，用在支持正则表达式的引擎或者命令中。</p>
<p>在 Bash 中，通配符只有三个符号：<code>*</code>，<code>?</code>, <code>[]</code></p>
<table>
  <thead>
      <tr>
          <th>通配符</th>
          <th>作用</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>？</code></td>
          <td>匹配任意的单个字符</td>
      </tr>
      <tr>
          <td><code>*</code></td>
          <td>匹配任意的多个字符</td>
      </tr>
      <tr>
          <td><code>**</code></td>
          <td>匹配任意级别目录(bash 4.0以上版本支持，<strong>shopt -s globstar</strong>)</td>
      </tr>
      <tr>
          <td><code>[]</code></td>
          <td>匹配一个单字符范围,如[a-z],[0-9],特殊用法可以参考上面的特殊符号表，^亦可表示反向</td>
      </tr>
  </tbody>
</table>
<blockquote>
<p>注意 \ 或者 <code>“ ”</code> <code>‘’</code> 都会使得通配符失效。</p>
</blockquote>
<p>一些具体的用法：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">ls *.txt               <span class="c1"># 匹配全部后缀为.txt的文件</span>
</span></span><span class="line"><span class="cl">ls file?.log           <span class="c1"># 匹配file1.log, file2.log, ...</span>
</span></span><span class="line"><span class="cl">ls <span class="o">[</span>a-z<span class="o">]</span>*.log          <span class="c1"># 匹配a-z开头的.log文件</span>
</span></span><span class="line"><span class="cl">ls <span class="o">[</span>^a-z<span class="o">]</span>*.log         <span class="c1"># 上面的反向匹配</span>
</span></span><span class="line"><span class="cl">ls /etc/**/*.conf      <span class="c1"># etc中任意多级目录下的conf文件。</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="fi">Fi</h2>
<p>正则部分的基本内容就是上述的这些，后续如果有遇到一些特殊的用法，以及进阶的用法会在上述补充；基础的正则规则了解后，介绍 grep 的使用，并基于 grep 的使用对正则表达式进行练习。</p>
]]></content:encoded>
    </item>
    <item>
      <title>内网穿透（NAT穿透）</title>
      <link>https://aikenh.cn/posts/nat%E7%A9%BF%E9%80%8F/</link>
      <pubDate>Tue, 04 Apr 2023 14:40:12 +0000</pubDate>
      <guid>https://aikenh.cn/posts/nat%E7%A9%BF%E9%80%8F/</guid>
      <description>理解内网穿透的原理和简单实现</description>
      <content:encoded><![CDATA[<p>本文简要介绍对内网穿透技术、对内网穿透技术的需求以及介绍一些用于&quot;个人&quot;进行内网穿透的工具和使用。</p>
<h2 id="1-什么是内网穿透nat-traversal">1. 什么是内网穿透(NAT traversal）</h2>
<p>在计算机科学中，<strong>NAT穿越</strong>（NAT traversal）涉及TCP/IP中的一个常见问题，即在处于使用了NAT设备的私有TCP/IP网络中的主机之间创建连接的问题。</p>
<p>其中 NAT 即<a href="https://zh.wikipedia.org/wiki/%E7%BD%91%E7%BB%9C%E5%9C%B0%E5%9D%80%E8%BD%AC%E6%8D%A2" target="_blank" rel="noopener">网络地址转换</a>
（Network Address Translation）在计算机网络中是一种在 IP 数据包通过路由器或防火墙时重写来源 IP 地址或目的 IP 地址的技术。<strong>这种技术被普遍使用在有多台主机但只通过一个公有 IP 地址访问互联网的私有网络中</strong>。它是一个方便且得到了广泛应用的技术。当然，NAT 也让主机之间的通信变得复杂，导致了通信效率的降低。</p>
<blockquote>
<p>NAT 是作为一种解决<a href="https://zh.wikipedia.org/wiki/IPv4%E4%BD%8D%E5%9D%80%E6%9E%AF%E7%AB%AD" title="IPv4位址枯竭" target="_blank" rel="noopener">IPv4地址短缺</a>
以避免保留 IP 地址困难的方案而流行起来的。NAT 成了家庭和小型办公室网络连接上的路由器的一个标准特征。</p>
</blockquote>
<p>其中最为常见的 NAT 设备就是家家户户都有的路由器，将所有的设备在<strong>局域网</strong>中统一管理，并基于唯一的公网 ip 对互联网（私有网络）进行访问。</p>
<p>而 NAT 会带来以下的问题，因此会需要内网穿透的技术：</p>
<ul>
<li>外网主动发起的服务无法准确的定位到内网的指定机器，会被 NAT 设备丢弃，因此链接会变成单项的，无法双向交互。</li>
</ul>
<p>因此无法在外网访问内网机器提供给局域网的服务，因此我们的机器，我们部署于 NAS、docker 的服务就只能在局域网中访问，在一定程度上就造成不便。</p>
<h2 id="2如何实现内网穿透">2.如何实现内网穿透</h2>
<p>解决方法也比较直观，在内网中建立一个代理服务器，其暴露在公网中，这样，通过直接访问该代理服务器进行中转，进而直接访问到指定的机器，这样其实就是建立了一个<a href="https://zh.wikipedia.org/wiki/%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86" target="_blank" rel="noopener">反向代理</a>
来实现内网穿透。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230405004156.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230405004156.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230405004156.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>反向代理如何理解呢，就正向代理而言，我们要访问的服务器 IP 是已知的，而我们自身是隐藏的，代理服务器是客户端的。</p>
<p>而反向代理则是我们要访问的服务器是隐藏的，我们需要借由代理服务器去访问它。</p>
<h2 id="3内网穿透工具">3.内网穿透工具</h2>
<ol>
<li>Zerotier</li>
<li><a href="https://github.com/ffay/lanproxy-go-client" target="_blank" rel="noopener">https://github.com/ffay/lanproxy-go-client</a>
</li>
<li><a href="https://github.com/jpillora/chisel/" target="_blank" rel="noopener">jpillora/chisel: A fast TCP/UDP tunnel over HTTP (github.com)</a>
</li>
<li>ngrok</li>
<li>tailscale</li>
</ol>
<p>使用 Zerotier 搭建内网穿透的话极其简单，这里就不在赘言，上述还包含了一些其他搭建内网穿透的工具。</p>
]]></content:encoded>
    </item>
    <item>
      <title>配置 MacOS 的终端</title>
      <link>https://aikenh.cn/posts/macos_bash_config/</link>
      <pubDate>Sun, 02 Apr 2023 19:28:48 +0000</pubDate>
      <guid>https://aikenh.cn/posts/macos_bash_config/</guid>
      <description>&lt;p&gt;Mac 的 Terminal 和 Ubuntu 的操作上较为相似，都是 Unix 的吧，但是要注意一下安全和软件管理库。&lt;/p&gt;
&lt;p&gt;其他的参考资料： &lt;a href=&#34;https://www.youtube.com/watch?v=RNqDkF17ogY&amp;amp;t=787s&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://www.youtube.com/watch?v=RNqDkF17ogY&amp;t=787s&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id=&#34;temrinal-终端&#34;&gt;Temrinal 终端&lt;/h2&gt;
&lt;p&gt;The default terminal is zsh, so we do not need to install zsh from scratch.&lt;/p&gt;
&lt;h3 id=&#34;brew&#34;&gt;Brew&lt;/h3&gt;
&lt;p&gt;we install brew follow the &lt;a href=&#34;https://brew.sh&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;official website&lt;/a&gt;
 settings :&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;div class=&#34;code-title&#34; onclick=&#34;toggleCode(this)&#34;&gt;
        
        &lt;span class=&#34;code-block-open&#34;&gt;&lt;ion-icon name=&#34;chevron-down-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/span&gt;
        &lt;span class=&#34;code-block-close&#34;&gt;&lt;ion-icon name=&#34;chevron-forward-outline&#34;&gt;&lt;/ion-icon&gt;&lt;/ion-icon&gt;&lt;/span&gt;
        &lt;span&gt;bash&lt;/span&gt;
    &lt;/div&gt;
    &lt;div class=&#34;code-content&#34;&gt;
        
        &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/bin/bash -c &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === &#34;none&#34; || codeContent.style.display === &#34;&#34;) {
        codeContent.style.display = &#34;block&#34;; 
        codeContent.parentNode.classList.remove(&#34;code-has-hidden-child&#34;);
    } else {
        codeContent.style.display = &#34;none&#34;; 
        codeContent.parentNode.classList.add(&#34;code-has-hidden-child&#34;);
    }
}
&lt;/script&gt;&lt;h3 id=&#34;iterm-2&#34;&gt;Iterm 2&lt;/h3&gt;
&lt;p&gt;After install brew we can install iterm 2 like this :&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Mac 的 Terminal 和 Ubuntu 的操作上较为相似，都是 Unix 的吧，但是要注意一下安全和软件管理库。</p>
<p>其他的参考资料： <a href="https://www.youtube.com/watch?v=RNqDkF17ogY&amp;t=787s" target="_blank" rel="noopener">https://www.youtube.com/watch?v=RNqDkF17ogY&t=787s</a>
</p>
<h2 id="temrinal-终端">Temrinal 终端</h2>
<p>The default terminal is zsh, so we do not need to install zsh from scratch.</p>
<h3 id="brew">Brew</h3>
<p>we install brew follow the <a href="https://brew.sh" target="_blank" rel="noopener">official website</a>
 settings :</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">/bin/bash -c <span class="s2">&#34;</span><span class="k">$(</span>curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh<span class="k">)</span><span class="s2">&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="iterm-2">Iterm 2</h3>
<p>After install brew we can install iterm 2 like this :</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">brew install iterm2 --cask</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>Then we download and config its&rsquo; setting in the preference menu. Or export the profile.</p>
<p>Those following settings are what i&rsquo;m most concerned about, and because of the simple UI, we will not introduce too much.</p>
<ul>
<li>Transparent</li>
<li>Snippets</li>
<li>Status line</li>
<li>Split windows</li>
</ul>
<p>这将会是我们的主终端应用，后续会结合 fig 一起使用，这给我们提供了媲美，甚至超越 windows terminal 的使用体验。</p>
<p>Seems like 可以取代 tmux 来进行分屏</p>
<p><strong>Themes</strong> &amp; <strong>Snipnet</strong></p>
<h3 id="fig">Fig</h3>
<p><strong><a href="https://github.com/withfig/autocomplete" target="_blank" rel="noopener">Fig</a>
 adds autocomplete to your terminal.</strong>  Install it from brew.</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">brew install fig --cask</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>After install Fig, we need to start the dashboard to config our terminal (vscode &amp; iterm 2)</p>
<h3 id="warp">Warp</h3>
<p>A modern terminal design for macOS, which is like terminal + fig + multi-tabs but without transparent.</p>
<p>we could download this from <a href="https://www.warp.dev" target="_blank" rel="noopener">warps</a>
, it provide another good  terminal experience.</p>
<p>Deprecate for now</p>
<h3 id="omz">Omz</h3>
<p>Like in all bash: <a href="https://ohmyz.sh/#install" target="_blank" rel="noopener">omz</a>
, Use it with <a href="https://github.com/romkatv/powerlevel10k" target="_blank" rel="noopener">powerlevel10k</a>
;</p>
<h3 id="neovim">NeoVim</h3>
<p>Configuration: We download the dotfile from our <a href="https://github.com/AikenH/configs_scripts" target="_blank" rel="noopener">GitHub rep</a>
 o then replace it.</p>
<p><a href="https://github.com/neovim/neovim/wiki/Installing-Neovim" target="_blank" rel="noopener">Download</a>
:</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">brew install --HEAD neovim</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="tar-的使用事项">Tar 的使用事项</h3>
<p>Mac 使用 tar 压缩，每个文件会多生成 <code>&quot;._&quot;</code> 文件副本，该文件在 mac 中解压的时候，他自己能删除这些多余的文件，而在多平台使用的时候，就会很麻烦，因此我们使用 <code>COPYFILE_DISABLE</code> 防止生成此类文件</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nv">COPYFILE_DISABLE</span><span class="o">=</span><span class="m">1</span> tar -zcvf files.tar files_dir</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="others">Others</h3>
<ul>
<li>Ranger</li>
<li>Zenith</li>
<li>Duf: disk usage/ free utility</li>
<li>Dust: file tree</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Whats DevOps?</title>
      <link>https://aikenh.cn/posts/devops/</link>
      <pubDate>Sat, 25 Mar 2023 09:55:32 +0000</pubDate>
      <guid>https://aikenh.cn/posts/devops/</guid>
      <description>Explain Devops, CI, CD and How it works</description>
      <content:encoded><![CDATA[<p>在一个庞大的组织架构中，CI/CD 和 Devops 的概念是避不开的，了解它的工作原理和概念能帮助我们更好的与他人进行协作。</p>
<h2 id="cicd-介绍">CI/CD 介绍</h2>
<div style="text-align:center">
    <img src= https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230403173436.png title="devops">
</div>
<p>这是一个用来描绘 CI/CD 的示意图，其描绘了 CI/CD 的工作流和各自的一些职责，接下来本文分别对两者进行介绍。</p>
<h3 id="ci-continuous-integration-持续集成">CI (Continuous integration) 持续集成</h3>
<p>持续集成是面向开发者（Developer）的环节。从上述的图也可以看出，整体的流程如下：</p>
<p>Developer 基于给出的需求进行<strong>编码（code）</strong>，完成 Feature 或者 Bug 修复后，<strong>提交（Commit）代码</strong>，然后平台会对这些需要（Merge Request）代码进行<strong>编译（Build）</strong>，编译通过后，执行自动化的<strong>持续测试（Continuous Test）</strong>，待测试通过后才会正式合并入主干。</p>
<p>也就是说，CI 工具在检测到代码变更后，自动对其执行编译和单元测试，验证其代码的正确性和可用性，以及是否适合与源代码进行集成，然后进行自动集成。</p>
<p>该流程有以下的优势：</p>
<ul>
<li>能够避免不同开发环境带来的不一致问题</li>
<li>减少手动操作</li>
<li>清晰的版本管理和控制</li>
<li>降低人为操作的风险</li>
</ul>
<h3 id="cd-continuous-deployment持续部署">CD (Continuous deployment)持续部署</h3>
<p>持续部署则是面向 IT 运维技术人员（ops）的环节，整体流程如下：</p>
<p>Devs 成功 <strong>发布代码(release)</strong> 后，CD 工具会自动 <strong>部署（deploy）</strong> 该 service 到服务器上，进行发布，直接部署到生产环境中，可供 <strong>操作（operate）</strong>，并通过 <strong>监控（monitor）</strong> 来确保服务的正常运行，如果出现问题后，就即时 FeedBack 给开发者。</p>
<blockquote>
<p>持续交付是一种软件开发实践，它与 CI 结合使用，可自动执行基础结构预配和应用程序发布过程。作为 CI 过程的一部分测试和构建代码后，CD 会在最后阶段接管，以确保它包含随时部署到任何环境所需的一切。CD 可以涵盖从调配基础结构到将应用程序部署到测试或生产环境的所有内容。使用 CD，软件的构建使其可以随时部署到生产环境。然后，可以手动触发部署或移动到持续部署，其中部署也是自动化的。</p>
</blockquote>
<p>该流程提供了这样的能力：</p>
<ul>
<li>确保随时随地能进行部署</li>
<li>确保更新能够正常执行</li>
</ul>
<h3 id="ct-continuous-test-持续测试">CT (Continuous Test) 持续测试</h3>
<blockquote>
<p>持续测试是一种软件测试实践，其中测试持续运行，以便在错误引入代码库后立即识别错误。在 CI/CD 管道中，持续测试通常是自动执行的，每次代码更改都会触发一系列测试，以确保应用程序仍按预期工作。</p>
</blockquote>
<p>持续测试能够在早期就识别潜在的问题，也能在交付的初期发现 Bug，避免后期 Debug 的困难，也能帮助提示和提高开发人员的代码质量，其主要依赖的测试类型为：</p>
<ul>
<li><strong>单元测试</strong>，检查各个代码<strong>单元</strong>是否按预期工作</li>
<li><strong>集成测试</strong>，验证应用程序中的不同模块或服务如何协同工作</li>
<li><strong>回归测试</strong>，在修复错误后执行，以确保特定错误不会再次发生</li>
</ul>
<h3 id="cicd工具介绍">CI/CD工具介绍</h3>
<p>该部分内容来自 <a href="%20[Day12%20%e4%bb%80%e9%ba%bc%e6%98%af%20CICD%20-%20iT%20%e9%82%a6%e5%b9%ab%e5%bf%99::%e4%b8%80%e8%b5%b7%e5%b9%ab%e5%bf%99%e8%a7%a3%e6%b1%ba%e9%9b%a3%e9%a1%8c%ef%bc%8c%e6%8b%af%e6%95%91%20IT%20%e4%ba%ba%e7%9a%84%e4%b8%80%e5%a4%a9%20%28ithome.com.tw%29]%28https://ithelp.ithome.com.tw/articles/10219083%29%20">reference</a>
 该文</p>
<ul>
<li>GitLab (Version Control)</li>
<li>GitHub (Version Control)</li>
<li>Jenkins (自动 build 工具)</li>
<li>Drone (自动 build 工具)</li>
<li>Circle (自动 build 工具)</li>
<li>Docker (迅速佈署環境工具)</li>
<li>K8S (管理 Docker Container 工具)</li>
<li>Helm (快速建置各環境 K8S 工具)</li>
<li>Grafana (機器數據監控工具)</li>
<li>ELK (Log 蒐集工具)</li>
<li>Telegram (通訊、錯誤通知工具)</li>
<li>Slack (通訊、錯誤通知工具)</li>
</ul>
<h3 id="cicd-的优点">CI/CD 的优点</h3>
<p>参考 Gitlab 该文中的相关部分 <a href="https://about.gitlab.com/topics/ci-cd/" target="_blank" rel="noopener">什么是 CI/CD？ |吉特实验室 (gitlab.com)</a>
，无非是更安全，更快速，更透明，更易于开发，减少 merge 地狱。</p>
<h2 id="devops-介绍">DevOps 介绍</h2>
<p>DevOps 实际上是一种方法论：主要强调软件开发测试运维的一体化，目标是减少各个部门之间的沟通成本从而实现软件的快速高质量的发布。</p>
<blockquote>
<p>（<strong>Dev</strong>elopment和<strong>Op</strong>erations的<a href="https://zh.wikipedia.org/wiki/%E6%B7%B7%E6%88%90%E8%A9%9E" title="混成词" target="_blank" rel="noopener">混成词</a>
）是一种重视“软件开发人员（Dev）”和“IT运维技术人员（Ops）”之间沟通合作的文化、运动或惯例。通过自动化“软件交付”和“架构变更”的流程，来使得构建、测试、发布软件能够更加地快捷、频繁和可靠。</p>
</blockquote>
<p>而 CI/CD 实际上就是 DevOps 的核心，可以看下面这张图，实际上与 CI、CD 高度重合，但是 DevOps 并不完全等同于 CI/CD，要实现 DevOps 还依靠公司的各种架构组织等。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230403212256.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230403212256.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230403212256.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>下面这些是对应的工作流和相应的软件：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230403212454.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230403212454.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230403212454.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>


<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230403212516.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230403212516.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230403212516.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>


<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230403212527.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230403212527.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230403212527.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>


<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/v2-681fb4c6f6fac9cb893b623d74bab09d_r.jpg">
    <img alt="v2-681fb4c6f6fac9cb893b623d74bab09d_r.jpg" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/v2-681fb4c6f6fac9cb893b623d74bab09d_r.jpg"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/v2-681fb4c6f6fac9cb893b623d74bab09d_r.jpg" style="display: block; margin: 0 auto;"
      alt="v2-681fb4c6f6fac9cb893b623d74bab09d_r.jpg"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="reference">Reference</h2>
<ul>
<li><a href="https://ithelp.ithome.com.tw/articles/10219083" target="_blank" rel="noopener">Day12 什麼是 CICD - iT 邦幫忙::一起幫忙解決難題，拯救 IT 人的一天 (ithome.com.tw)</a>
</li>
<li><a href="https://blog.jjonline.cn/linux/238.html" target="_blank" rel="noopener">DevOps漫谈之一：DevOps、CI、CD都是什么鬼？ - 晶晶的博客 (jjonline.cn)</a>
</li>
<li><a href="https://about.gitlab.com/topics/ci-cd/" target="_blank" rel="noopener">什么是 CI/CD？ |吉特实验室 (gitlab.com)</a>
</li>
<li><a href="https://www.synopsys.com/glossary/what-is-cicd.html" target="_blank" rel="noopener">What Is CI/CD and How Does It Work? | Synopsys</a>
</li>
<li><a href="https://github.blog/2022-02-02-build-ci-cd-pipeline-github-actions-four-steps/" target="_blank" rel="noopener">How to build a CI/CD pipeline with GitHub Actions in four simple steps | The GitHub Blog</a>
</li>
<li><a href="https://en.wikipedia.org/wiki/CI/CD" target="_blank" rel="noopener">CI/CD - Wikipedia</a>
</li>
<li><a href="https://en.wikipedia.org/wiki/DevOps" target="_blank" rel="noopener">DevOps - Wikipedia</a>
</li>
<li><a href="https://zhuanlan.zhihu.com/p/127093414" target="_blank" rel="noopener">持续集成cicd和devops - 知乎 (zhihu.com)</a>
</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>折腾 Hexo 的 Icarus 主题</title>
      <link>https://aikenh.cn/posts/custom_icarus/</link>
      <pubDate>Sat, 11 Mar 2023 23:46:37 +0000</pubDate>
      <guid>https://aikenh.cn/posts/custom_icarus/</guid>
      <description>基于Icarus的主题的个人配置</description>
      <content:encoded><![CDATA[<p>本文的博客页面基于 <a href="[Hexo]%28https://hexo.io/zh-cn/%29">Hexo</a>
+<a href="https://ppoffice.github.io/" target="_blank" rel="noopener">Icarus</a>
 主题搭建，在使用过程中对该主题做了一些简单的配置，以适应自己的需求。这里介绍一下自己粗浅的方案。</p>
<blockquote>
<p>十分推荐 Icarus 这个主题，功能支持十分全面而且作者的文档也较为详实，推荐大家去了解。</p>
</blockquote>
<h2 id="拓宽显示页面区域">拓宽显示页面区域</h2>
<p><code>include/style/base.styl</code>  中定义了各种基本页面尺寸：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">$gap</span> <span class="o">?=</span> <span class="mi">64</span><span class="nx">px</span>
</span></span><span class="line"><span class="cl"><span class="nx">$tablet</span> <span class="o">?=</span> <span class="mi">769</span><span class="nx">px</span>
</span></span><span class="line"><span class="cl"><span class="nx">$desktop</span> <span class="o">?=</span> <span class="mi">1088</span><span class="nx">px</span>
</span></span><span class="line"><span class="cl"><span class="nx">$widescreen</span> <span class="o">?=</span> <span class="mi">1280</span><span class="nx">px</span>
</span></span><span class="line"><span class="cl"><span class="nx">$fullhd</span> <span class="o">?=</span> <span class="mi">1472</span><span class="nx">px</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以在 <code>include/style/responsive.styl</code>  中定义 2 栏 3 栏情况下所使用的宽度：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="o">+</span><span class="nx">widescreen</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">is</span><span class="o">-</span><span class="mi">3</span><span class="o">-</span><span class="nx">column</span> <span class="p">.</span><span class="nx">container</span>
</span></span><span class="line"><span class="cl">        <span class="nx">max</span><span class="o">-</span><span class="nx">width</span><span class="o">:</span> <span class="nx">$fullhd</span><span class="o">-</span> <span class="nx">$gap</span>
</span></span><span class="line"><span class="cl">        <span class="nx">width</span><span class="o">:</span> <span class="nx">$fullhd</span> <span class="o">-</span> <span class="nx">$gap</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">is</span><span class="o">-</span><span class="mi">1</span><span class="o">-</span><span class="nx">column</span> <span class="p">.</span><span class="nx">container</span><span class="p">,</span> <span class="p">.</span><span class="nx">is</span><span class="o">-</span><span class="mi">2</span><span class="o">-</span><span class="nx">column</span> <span class="p">.</span><span class="nx">container</span>
</span></span><span class="line"><span class="cl">        <span class="nx">max</span><span class="o">-</span><span class="nx">width</span><span class="o">:</span> <span class="nx">$widescreen</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="nx">$gap</span>
</span></span><span class="line"><span class="cl">        <span class="nx">width</span><span class="o">:</span> <span class="nx">$widescreen</span><span class="o">-</span> <span class="mi">2</span> <span class="o">*</span> <span class="nx">$gap</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="移动端优化">移动端优化</h2>
<p>该主题在移动端表现的时候，两侧的 widget 会自动挪到下方，这样每个文章看完的时候体验很差，所以我希望在移动端的时候能隐藏这些 widget。</p>
<p><code>source/js/main.js</code> 中仿照下面的格式添加对应 widget 的 type 即可：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">$</span><span class="p">(</span><span class="s1">&#39;div.container div.card[data-type=categories]&#39;</span><span class="p">).</span><span class="nx">addClass</span><span class="p">(</span><span class="s1">&#39;is-hidden-mobile&#39;</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>但是该代码会有问题，就是相应 disable 的 widget 对应的单独界面在移动端会失效。</p>
<h2 id="自定义-404-界面">自定义 404 界面</h2>
<p>在 hexo 的默认配置（非 icarus 的配置）<code>_config.yml</code> 中跳过对 404.html 的渲染，直接使用该静态 html 页面进行页面的配置。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yml" data-lang="yml"><span class="line"><span class="cl"><span class="nt">skil_render</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span>- <span class="m">404.</span><span class="l">html</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>404 静态页面可以使用腾讯公益界面，或者网上找一个<a href="https://freefrontend.com/html-css-404-page-templates/" target="_blank" rel="noopener">模版</a>
使用，效果如下：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230312150155.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230312150155.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230312150155.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="夜间模式切换-variant">夜间模式（切换 variant）</h2>
<p>夜间模式的实现主要参考<a href=""></a>
，网上大多用的都是这个方案，但是个人非常喜欢 cyberpunk 的变体，所以希望实现夜间模式的时候切换成 cyberpunk 的 variant ，本文基于其实现做了一些改动，基本实现了该功能，但是目前而言还存在一些问题。</p>
<blockquote>
<p>本人不是很懂前端，因此这个 dom 加载完成后重新加载 css 过程中，导致的页面畸变问题目前不知道该如何解决，望前端大大给点指导</p>
</blockquote>
<h3 id="添加主题切换按钮">添加主题切换按钮</h3>
<p>在 <code>layout/common/navbar.jsx</code> 中添加夜间模式切换按钮，绑定 <code>night-nav</code> 事件，</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>jsx</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="c1">//{showSearch ? &lt;a class=&#34;navbar-item search&#34; title={searchTitle} href=&#34;javascript:;&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="c1">//	&lt;i class=&#34;fas fa-search&#34;&gt;&lt;/i&gt;
</span></span></span><span class="line"><span class="cl"><span class="c1">//&lt;/a&gt; : null}
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;navbar-item night&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;night-nav&#34;</span> <span class="na">title</span><span class="o">=</span><span class="s">&#34;Night Mode&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;javascript:;&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">i</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;fas fa-lightbulb&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;night-icon&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">i</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="预先载入两个-css-文件">预先载入两个 css 文件</h3>
<p>在 <code>layout/common/head.jsx</code> 中预先载入可选的第二个 stylesheet（css 文件）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>jsx</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsx" data-lang="jsx"><span class="line"><span class="cl"><span class="p">{</span><span class="cm">/* &lt;link rel=&#34;stylesheet&#34; href={url_for(&#39;/css/&#39; + variant + &#39;.css&#39;)} /&gt; */</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">href</span><span class="o">=</span><span class="p">{</span><span class="nx">url_for</span><span class="p">(</span><span class="s1">&#39;/css/&#39;</span> <span class="o">+</span> <span class="s1">&#39;default&#39;</span> <span class="o">+</span> <span class="s1">&#39;.css&#39;</span><span class="p">)}</span> <span class="na">title</span><span class="o">=</span><span class="s">&#39;default&#39;</span><span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;alternate stylesheet&#34;</span> <span class="na">href</span><span class="o">=</span><span class="p">{</span><span class="nx">url_for</span><span class="p">(</span><span class="s1">&#39;/css/&#39;</span> <span class="o">+</span> <span class="s1">&#39;cyberpunk&#39;</span> <span class="o">+</span> <span class="s1">&#39;.css&#39;</span><span class="p">)</span> <span class="p">}</span> <span class="na">title</span><span class="o">=</span><span class="s">&#39;cyberpunk&#39;</span><span class="p">/&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="编写-js-实现-css-跳转">编写 js 实现 css 跳转</h3>
<p>本部分主要来自 <a href="https://www.imaegoo.com/" target="_blank" rel="noopener">imagegoo</a>
 的夜间模式实现，修改了一下其调用的文件和变体变量，在 <code>source/js/night.js</code> 中实现。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="p">(</span><span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm">     * Icarus 夜间模式 by iMaeGoo
</span></span></span><span class="line"><span class="cl"><span class="cm">     * https://www.imaegoo.com/
</span></span></span><span class="line"><span class="cl"><span class="cm">        */</span>
</span></span><span class="line"><span class="cl">      <span class="kd">var</span> <span class="nx">isNight</span> <span class="o">=</span> <span class="nx">localStorage</span><span class="p">.</span><span class="nx">getItem</span><span class="p">(</span><span class="s1">&#39;default&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="kd">var</span> <span class="nx">nightNav</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="kd">function</span> <span class="nx">applyNight</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">$</span><span class="p">(</span><span class="nb">window</span><span class="p">).</span><span class="nx">trigger</span><span class="p">(</span><span class="s1">&#39;resize&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nx">value</span><span class="p">.</span><span class="nx">toString</span><span class="p">()</span> <span class="o">===</span> <span class="s1">&#39;true&#39;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// document.body.classList.remove(&#39;light&#39;);
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="c1">// document.body.classList.add(&#39;night&#39;);
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="nx">setStyleSheet</span><span class="p">(</span><span class="s1">&#39;cyberpunk&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            
</span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// document.body.classList.remove(&#39;night&#39;);
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="c1">// document.body.classList.add(&#39;light&#39;);
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="nx">setStyleSheet</span><span class="p">(</span><span class="s1">&#39;default&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="kd">function</span> <span class="nx">findNightNav</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">nightNav</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">&#39;night-nav&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">nightNav</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">setTimeout</span><span class="p">(</span><span class="nx">findNightNav</span><span class="p">,</span> <span class="mi">100</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">nightNav</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;click&#39;</span><span class="p">,</span> <span class="nx">switchNight</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="kd">function</span> <span class="nx">switchNight</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">location</span><span class="p">.</span><span class="nx">reload</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="nx">isNight</span> <span class="o">=</span> <span class="nx">isNight</span> <span class="o">?</span> <span class="nx">isNight</span><span class="p">.</span><span class="nx">toString</span><span class="p">()</span> <span class="o">!==</span> <span class="s1">&#39;true&#39;</span> <span class="o">:</span> <span class="kc">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nx">applyNight</span><span class="p">(</span><span class="nx">isNight</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nx">localStorage</span><span class="p">.</span><span class="nx">setItem</span><span class="p">(</span><span class="s1">&#39;default&#39;</span><span class="p">,</span> <span class="nx">isNight</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">function</span> <span class="nx">setStyleSheet</span><span class="p">(</span><span class="nx">title</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="kd">var</span> <span class="nx">link_list</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByTagName</span><span class="p">(</span><span class="s2">&#34;link&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nx">link_list</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">            <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="nx">i</span><span class="o">&lt;</span><span class="nx">link_list</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span> <span class="p">(</span><span class="nx">link_list</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">getAttribute</span><span class="p">(</span><span class="s2">&#34;rel&#34;</span><span class="p">).</span><span class="nx">indexOf</span><span class="p">(</span><span class="s2">&#34;style&#34;</span><span class="p">)</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span> <span class="o">&amp;&amp;</span> <span class="nx">link_list</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">getAttribute</span><span class="p">(</span><span class="s2">&#34;title&#34;</span><span class="p">)){</span>
</span></span><span class="line"><span class="cl">                    <span class="nx">link_list</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">disabled</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                    <span class="k">if</span> <span class="p">(</span><span class="nx">link_list</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">getAttribute</span><span class="p">(</span><span class="s2">&#34;title&#34;</span><span class="p">)</span> <span class="o">==</span> <span class="nx">title</span><span class="p">)</span> <span class="nx">link_list</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">disabled</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">    <span class="nx">findNightNav</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">isNight</span> <span class="o">&amp;&amp;</span> <span class="nx">applyNight</span><span class="p">(</span><span class="nx">isNight</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}());</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>并在 <code>layout/common</code> 完成对该 js 的引入。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl">	<span class="o">&lt;</span><span class="nx">script</span> <span class="nx">src</span><span class="o">=</span><span class="p">{</span><span class="nx">url_for</span><span class="p">(</span><span class="s1">&#39;/js/main.js&#39;</span><span class="p">)}</span> <span class="nx">defer</span><span class="o">&gt;&lt;</span><span class="err">/script&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="o">&lt;</span><span class="nx">script</span> <span class="nx">src</span><span class="o">=</span><span class="p">{</span><span class="nx">url_for</span><span class="p">(</span><span class="s1">&#39;/js/night.js&#39;</span><span class="p">)}</span> <span class="nx">defer</span><span class="o">=</span><span class="p">{</span><span class="kc">true</span><span class="p">}</span><span class="o">&gt;&lt;</span><span class="err">/script&gt;</span>
</span></span><span class="line"><span class="cl"><span class="o">&lt;</span><span class="err">/Fragment&gt;;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="添加访客数和访问次数">添加访客数和访问次数</h2>
<p>该主题原本就支持 busuanzi 的访客统计，在设置中打开就行，但是只显示其中一种，如果想要全部打开，可以仿照其原本的补充编写：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="c1">// 在如下的地方依照类似的方法添加访客计数pv
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">visitorCounterTitle</span><span class="o">:</span> <span class="nx">_p</span><span class="p">(</span><span class="s1">&#39;plugin.visitor_count&#39;</span><span class="p">,</span> <span class="s1">&#39;&lt;span id=&#34;busuanzi_value_site_uv&#34;&gt;0&lt;/span&gt;&#39;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="nx">visitorCounterTitle</span><span class="o">:</span> <span class="nx">_p</span><span class="p">(</span><span class="s1">&#39;plugin.visitor_count&#39;</span><span class="p">,</span> <span class="s1">&#39;&lt;span id=&#34;busuanzi_value_site_pv&#34;&gt;0&lt;/span&gt;&#39;</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>同样对该值的调用和渲染也要到相应的地方注册。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">visitorCounterTitle</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="nx">visitCounterTitle</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>并添加渲染：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="p">{</span><span class="nx">showVisitorCounter</span> <span class="o">?</span> <span class="o">&lt;</span><span class="nx">span</span> <span class="nx">id</span><span class="o">=</span><span class="s2">&#34;busuanzi_container_site_pv&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="nx">dangerouslySetInnerHTML</span><span class="o">=</span><span class="p">{{</span> <span class="nx">__html</span><span class="o">:</span> <span class="nx">visitorCounterTitle</span> <span class="p">}}</span><span class="o">&gt;&lt;</span><span class="err">/span&gt; : null}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">{</span><span class="nx">showVisitorCounter</span> <span class="o">?</span> <span class="s2">&#34; and &#34;</span><span class="o">:</span> <span class="kc">null</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="p">{</span><span class="nx">showVisitorCounter</span> <span class="o">?</span> <span class="o">&lt;</span><span class="nx">span</span> <span class="nx">id</span><span class="o">=</span><span class="s2">&#34;busuanzi_container2_site_uv&#34;</span>
</span></span><span class="line"><span class="cl">		<span class="nx">dangerouslySetInnerHTML</span><span class="o">=</span><span class="p">{{</span> <span class="nx">__html</span><span class="o">:</span> <span class="nx">visitCounterTitle</span> <span class="p">}}</span><span class="o">&gt;&lt;</span><span class="err">/span&gt; : null}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="所有图片居中">所有图片居中</h2>
<p>参考资料：<a href="https://github.com/ppoffice/hexo-theme-icarus/issues/386" target="_blank" rel="noopener">请问如何实现文章中图片居中显示</a>
</p>
<p>单张图片居中可以使用：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="o">&lt;</span><span class="nx">div</span> <span class="nx">style</span><span class="o">=</span><span class="s2">&#34;text-align:center&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="nx">img</span> <span class="nx">src</span><span class="o">=</span> <span class="nx">https</span><span class="o">:</span><span class="c1">//picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230403173436.png title=&#34;devops&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="o">&lt;</span><span class="err">/div&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>全部图片居中可以在 hexo-theme-icarus/source/css/style.styl 中的 article 部分添加如下的最后四行：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>javascript</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="p">.</span><span class="nx">article</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">article</span><span class="o">-</span><span class="nx">meta</span>
</span></span><span class="line"><span class="cl">        <span class="nx">margin</span><span class="o">-</span><span class="nx">bottom</span><span class="o">:</span> <span class="mf">0.5</span><span class="nx">rem</span> <span class="o">!</span><span class="nx">important</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">content</span>
</span></span><span class="line"><span class="cl">        <span class="nx">font</span><span class="o">-</span><span class="nx">size</span><span class="o">:</span> <span class="mf">1.1</span><span class="nx">rem</span>
</span></span><span class="line"><span class="cl">        <span class="nx">blockquote</span><span class="p">.</span><span class="nx">pullquote</span>
</span></span><span class="line"><span class="cl">            <span class="kr">float</span><span class="o">:</span> <span class="nx">right</span>
</span></span><span class="line"><span class="cl">            <span class="nx">max</span><span class="o">-</span><span class="nx">width</span><span class="o">:</span> <span class="mi">50</span><span class="o">%</span>
</span></span><span class="line"><span class="cl">            <span class="nx">font</span><span class="o">-</span><span class="nx">size</span><span class="o">:</span> <span class="mf">1.15</span><span class="nx">rem</span>
</span></span><span class="line"><span class="cl">            <span class="nx">position</span><span class="o">:</span> <span class="nx">relative</span>
</span></span><span class="line"><span class="cl">        <span class="nx">a</span>
</span></span><span class="line"><span class="cl">            <span class="nx">img</span>
</span></span><span class="line"><span class="cl">                <span class="nx">margin</span><span class="o">:</span> <span class="nx">auto</span>
</span></span><span class="line"><span class="cl">                <span class="nx">display</span><span class="o">:</span> <span class="nx">block</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>新版的修改的地址已经迁移到：<code>themes/icarus/include/style/article.styl</code> 中,同样还是找到这一段描述中添加最后四行即可。</p>
<h2 id="文章以更新时间排序">文章以更新时间排序</h2>
<p>修改 <code>node_modules\hexo-generator-index\lib\generator.js</code> 文件为以下内容重新 <code>hexo s</code> 即可：</p>
<blockquote>
<p>修改之前记得备份</p>
</blockquote>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="s1">&#39;use strict&#39;</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">pagination</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;hexo-pagination&#39;</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">locals</span><span class="p">){</span>  
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">config</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">config</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">posts</span> <span class="o">=</span> <span class="nx">locals</span><span class="p">.</span><span class="nx">posts</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl">    <span class="nx">posts</span><span class="p">.</span><span class="nx">data</span> <span class="o">=</span> <span class="nx">posts</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">sort</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">        <span class="k">if</span><span class="p">(</span><span class="nx">a</span><span class="p">.</span><span class="nx">top</span> <span class="o">&amp;&amp;</span> <span class="nx">b</span><span class="p">.</span><span class="nx">top</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 当两篇文章top都有定义时  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="k">if</span><span class="p">(</span><span class="nx">a</span><span class="p">.</span><span class="nx">top</span> <span class="o">==</span> <span class="nx">b</span><span class="p">.</span><span class="nx">top</span><span class="p">)</span> <span class="k">return</span> <span class="nx">b</span><span class="p">.</span><span class="nx">updated</span> <span class="o">-</span> <span class="nx">a</span><span class="p">.</span><span class="nx">updated</span><span class="p">;</span> <span class="c1">// 若top值一样，则按照文章更新日期降序排列  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="k">else</span> <span class="k">return</span> <span class="nx">b</span><span class="p">.</span><span class="nx">top</span> <span class="o">-</span> <span class="nx">a</span><span class="p">.</span><span class="nx">top</span><span class="p">;</span> <span class="c1">// 否则按照top值降序排列  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="p">}</span>  
</span></span><span class="line"><span class="cl">        <span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="nx">a</span><span class="p">.</span><span class="nx">top</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="nx">b</span><span class="p">.</span><span class="nx">top</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 以下两种情况是若只有一篇文章top有定义，则将有top的排在前面（这里用异或操作居然不行233）  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl">        <span class="p">}</span>  
</span></span><span class="line"><span class="cl">        <span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">a</span><span class="p">.</span><span class="nx">top</span> <span class="o">&amp;&amp;</span> <span class="nx">b</span><span class="p">.</span><span class="nx">top</span><span class="p">)</span> <span class="p">{</span> <span class="c1">//上一条已解释  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl">        <span class="p">}</span>  
</span></span><span class="line"><span class="cl">        <span class="k">else</span> <span class="k">return</span> <span class="nx">b</span><span class="p">.</span><span class="nx">updated</span> <span class="o">-</span> <span class="nx">a</span><span class="p">.</span><span class="nx">updated</span><span class="p">;</span> <span class="c1">// 若都没定义，则按照文章更新日期降序排列  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">});</span>  
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">paginationDir</span> <span class="o">=</span> <span class="nx">config</span><span class="p">.</span><span class="nx">pagination_dir</span> <span class="o">||</span> <span class="s1">&#39;page&#39;</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">pagination</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="nx">posts</span><span class="p">,</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="nx">perPage</span><span class="o">:</span> <span class="nx">config</span><span class="p">.</span><span class="nx">index_generator</span><span class="p">.</span><span class="nx">per_page</span><span class="p">,</span>  
</span></span><span class="line"><span class="cl">    <span class="nx">layout</span><span class="o">:</span> <span class="p">[</span><span class="s1">&#39;index&#39;</span><span class="p">,</span> <span class="s1">&#39;archive&#39;</span><span class="p">],</span>  
</span></span><span class="line"><span class="cl">    <span class="nx">format</span><span class="o">:</span> <span class="nx">paginationDir</span> <span class="o">+</span> <span class="s1">&#39;/%d/&#39;</span><span class="p">,</span>  
</span></span><span class="line"><span class="cl">    <span class="nx">data</span><span class="o">:</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">      <span class="nx">__index</span><span class="o">:</span> <span class="kc">true</span>  
</span></span><span class="line"><span class="cl">    <span class="p">}</span>  
</span></span><span class="line"><span class="cl">  <span class="p">});</span>  
</span></span><span class="line"><span class="cl"><span class="p">};</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="troubleshooting">Troubleshooting</h2>
<h3 id="map-迭代错误">map 迭代错误</h3>
<p>执行 <code>hexo cl &amp;&amp; hexo g</code> 会出现以下的错误：</p>
<blockquote>
<p>Uncaught TypeError: Cannot read properties of undefined (reading ‘map‘)</p>
</blockquote>
<p>该错误主要是由于使用 map 进行循环之前未判断变量是否非空，导致对 undefined 变量做遍历导致，因此只需要在循环之前加上判断即可。</p>
<p>主要出错的是在一下的两个文件里：</p>
<ul>
<li>Layout/category.Jsx</li>
<li>Layout/index.Jsx</li>
</ul>
<p>使用如下的方式在使用 map 对变量进行遍历之前做一个非空判断：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231031000315.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231031000315.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20231031000315.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><a href="https://blog.csdn.net/fangqi20170515/article/details/126030610" target="_blank" rel="noopener">在react中使用map遍历，出现错误：Uncaught TypeError: Cannot read properties of undefined (reading ‘map‘)_学习前端的渣渣的博客-CSDN博客</a>
</p>
<h3 id="spawn-failed-解决方法">spawn failed 解决方法</h3>
<p>执行 <code>hexo d</code> 进行部署的时候可能会遇到 spawn failed 的各种问题，主要有两种情况</p>
<ul>
<li>网络问题</li>
<li>文件结构问题</li>
</ul>
<p>网络问题可以使用 <code>ss -T git@github</code> 测试连接情况；而文件结构问题的话，其实就是我们的链接库 <code>.deploy_git</code> 文件夹无法正常推送到 github，这种情况下可以考虑以下几种解决方式：</p>
<ul>
<li>【重置部署文件夹】 删除 <code>.depoly_git</code> 文件夹，重新执行 <code>hexo d</code></li>
<li>【不推荐】进入 <code>.deploy_git</code> 文件夹强制推送，<code>git push -f</code></li>
<li>【多系统编写导致文件混合编码问题】 <code>git config –global core.autocrlf false</code></li>
</ul>
<p>参考资料：<a href="https://blog.zhheo.com/p/128998ac.html" target="_blank" rel="noopener">Hexo错误：spawn failed的解决方法 | 张洪Heo (zhheo.com)</a>
</p>
<h2 id="reference">Reference</h2>
<ul>
<li><a href="https://www.imaegoo.com/2022/dec-27/" target="_blank" rel="noopener">博客主题源码和配置文件 - iMaeGoo&rsquo;s Blog</a>
</li>
<li><a href="https://karobben.github.io/2021/02/11/Blog/hexo_icarus/#Giscus" target="_blank" rel="noopener">Hexo theme: icarus| Highly personalize it - Karobben</a>
</li>
<li><a href="https://www.alphalxy.com/2019/03/customize-icarus/#%E7%9B%AE%E5%BD%95%E7%B2%98%E6%80%A7%E5%AE%9A%E4%BD%8D" target="_blank" rel="noopener">Icarus 主题自定义 - Alpha Lxy</a>
</li>
<li><a href="https://angericky.github.io/2018/12/24/icarus%E4%B8%AA%E6%80%A7%E5%AE%9A%E5%88%B6/" target="_blank" rel="noopener">hexo及icarus主题个性定制 - Jingjing&rsquo;s blog (angericky.github.io)</a>
</li>
<li><a href="https://ganzhixiong.com/" target="_blank" rel="noopener">干志雄的博客 (ganzhixiong.com)</a>
</li>
<li><a href="https://gsy00517.github.io/hexo20200207151318/" target="_blank" rel="noopener">hexo笔记：文章排序 | 高深远的博客 (gsy00517.github.io)</a>
</li>
</ul>
<p>and here are some theme I may want to try：</p>
<ul>
<li><a href="https://arknights.theme.hexo.yue.zone/" target="_blank" rel="noopener">Arknights (yue.zone)</a>
</li>
<li><a href="https://heliumoi.github.io/ringoExample/2022/07/07/Hexo-%E4%B8%BB%E9%A2%98-Ringo/" target="_blank" rel="noopener">Hexo 主题 Ringo - Hexo Theme Ringo (heliumoi.github.io)</a>
</li>
<li><a href="https://wiki.eryajf.net/" target="_blank" rel="noopener">二丫讲梵 (eryajf.net)</a>
</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Count_Min Sketch算法</title>
      <link>https://aikenh.cn/posts/countminsketch/</link>
      <pubDate>Fri, 10 Mar 2023 13:12:20 +0000</pubDate>
      <guid>https://aikenh.cn/posts/countminsketch/</guid>
      <description>计算大规模数据流中的元素出现频次的方法</description>
      <content:encoded><![CDATA[<p>本文介绍计算大规模数据流中的元素出现频次的方法 CMS，以及其简单改进Count-Mean-Min-Sketch</p>
<h2 id="intro--scene">Intro &amp; Scene</h2>
<p>在大数据场景下，比如网页的 TopK 问题，爬虫的是否访问过的问题，都是一种出现频次相关的问题，那么在系统设计的时候，如何选择策略和数据结构去存储相关的数据是最高效合适的呢？</p>
<p>计算元素的出现频次，如果出现与普通的场景下，简单的方案就是用 <code>hashmap</code> 来记录元素出现的次数：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">unordered_map</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">freq</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span><span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">e</span><span class="p">:</span> <span class="n">elements</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="p">(</span><span class="n">freq</span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="n">e</span><span class="p">)</span> <span class="o">==</span> <span class="n">freq</span><span class="p">.</span><span class="n">end</span><span class="p">()){</span>
</span></span><span class="line"><span class="cl">		<span class="n">freq</span><span class="p">[</span><span class="n">e</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span><span class="k">else</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="n">freq</span><span class="p">[</span><span class="n">e</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>但是这种方式在大量数据流的情况下，如果存在大量唯一元素的情况下，会占用大量的内存，导致其<strong>无法应对大数据场景</strong>，因此在&quot;时间换空间&quot;like 的策略选择中，这里就需要考虑通过时间，或者准确率等其他的因素来换空间。</p>
<p>通常来说，针对大数据场景，会无限扩张的数据结构显然是不适用的，所以希望能用固定的空间来进行计数的管理，同时希望尽量不要影响到运行的时间，换言之，可以牺牲掉一定的准确性，来实现节省空间的效果。</p>
<p>基于上述需求，我们可以想到 Hash 算法：将无限大的空间映射到固定的 size 的输出上；而大数据场景下的 Hash 会遇到冲突会被无限放大的问题，如何解决冲突是最核心的问题</p>
<ul>
<li>基于概率数据结构实现的 Blomm Filter 算法采取多 Hash 的方法来减少冲突</li>
<li>而其衍生出来的 CMS 算法以同样的思想，基于不同的设计，更为适应这种计数场景</li>
</ul>
<p>下面介绍该方法的具体实现</p>
<h2 id="cms-的具体实现">CMS 的具体实现</h2>
<p>首先第一点，通过 hash 来实现数值空间的转换，通过哈希函数 H 将输入元素 x 映射到一维数组上，通过该 index 的值来判断元素的 Count（是否存在）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp"># 伪代码
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">array</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="err">初始数组</span>
</span></span><span class="line"><span class="cl"><span class="nf">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">x</span> <span class="p">:</span> <span class="n">input_element</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="n">idx</span> <span class="o">=</span> <span class="n">H</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="n">array</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>实际上这就是 Blomm Filter 的基础思想，然而无论是定长数组的&quot;有限&quot;还是 Hash 函数本身，都需要考虑冲突问题（两个元素被映射到同一个 index 上），冲突会导致 Count 比真实的大。</p>
<p>于是接下来面临的问题就是：如何降低冲突的概率？如何提高计数的准确性（实际上也包含在降低冲突的概率中）</p>
<p>可以参考 Bloom Filter 的策略，其通过多个 Hash 函数来映射同一个数，从而来降低元素的冲突概率（未考虑超大数据场景），进而也能提高计数的准确性，那么我们看一下 bloom filter 方法：</p>
<blockquote>
<p>Bloom Filter 算法解决的是存在性问题，因此只需要一个 01 向量，当且仅当所有 Hash 计算出来的 index 的值都为 1 的时候，这个元素才可能存在；</p>
</blockquote>
<p>考虑将该方法向 Count 问题上迁移：</p>
<ul>
<li><strong>计数过程中</strong>：使用 n 个 Hash 函数计算 idx{1~n} ，然后 <code>vec[idx[i]] += 1</code> 对技术+1</li>
<li><strong>查询过程中</strong>：使用 n 个 Hash 函数计算 idx{1~n}，然后取 <code>vec[idx[i]]</code> 的最小值，考虑冲突场景可知，这个最小值&gt;=实际的 count。</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">query_count</span> <span class="o">=</span> <span class="n">INT_MAX</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">function_size</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">	<span class="kt">int</span> <span class="n">idx</span> <span class="o">=</span> <span class="n">Hash</span><span class="p">[</span><span class="n">i</span><span class="p">](</span><span class="n">query</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="kt">int</span> <span class="n">tmp_count</span> <span class="o">=</span> <span class="n">count_set</span><span class="p">[</span><span class="n">idx</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">	<span class="n">query_count</span> <span class="o">=</span> <span class="p">(</span><span class="n">tmp_count</span> <span class="o">&lt;</span> <span class="n">query_count</span><span class="p">)</span><span class="o">?</span> <span class="nl">tmp_count</span><span class="p">:</span> <span class="n">query_count</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>实际上取多个 hash 的最小值就是 Count-Min Sketch 的核心，但如果仅是如此很明显有个问题，就是多个 hash 函数算出的多个 idx 会进一步的“污染”计数，得不偿失，导致 Count 更加不准确。</p>
<p>实际上很容易想到，为了通过多个 hash 来减少冲突，并使得多 hash 的索引更加的唯一，最好的办法就是使得每个 hash 对应的计数空间是独立的，也就是将我们的计数空间在拓展成二维数组，其 size 为 $depth \times width$ 其中 depth 就代表 hash 函数的个数。</p>
<p>那么假设每个 Hash 函数的冲突概率是 $p_i$ 那么优化后的冲突概率就从 $min(P_i)$ 减小到</p>
<div>
$$ 
P = \prod_{i=1}^{n} p_i
 $$
</div>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">function_size</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">	<span class="kt">int</span> <span class="n">idx</span> <span class="o">=</span> <span class="n">Hash</span><span class="p">[</span><span class="n">i</span><span class="p">](</span><span class="n">query</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="kt">int</span> <span class="n">tmp_count</span> <span class="o">=</span> <span class="n">count_set</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">idx</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">	<span class="n">query_count</span> <span class="o">=</span> <span class="p">(</span><span class="n">tmp_count</span> <span class="o">&lt;</span> <span class="n">query_count</span><span class="p">)</span><span class="o">?</span> <span class="nl">tmp_count</span><span class="p">:</span> <span class="n">query_count</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>结合了这个二维数组就是完整的 CMS 算法了，最终求得的 count 是实际 Count 的近似值（上界）。</p>
<h3 id="cms-的参数选择">CMS 的参数选择</h3>
<p>如果确定使用 CMS，接下来面对的就是计数的精度问题，那么如何选择这个数组的 shape 才能尽可能的减少误差呢？（很明显都是越大越好，那么怎么样是最优/达标的呢）</p>
<p>确定一些变量参数：</p>
<ul>
<li>数据流大小： $n$</li>
<li>实际计数： $c_x$</li>
<li>估计计数： $\hat c_x$</li>
<li>hash 函数数目 $k$ ，存储向量长度 $w$</li>
</ul>
<p>设定误差范围：</p>
<div>
$$ (c_x \leq \hat c_x \leq c_x + \epsilon n) $$
</div>
<p>以及结果在这个范围内的概率为:</p>
<div>
$$ 
P(c_x \leq \hat c_x \leq c_x + \epsilon n) \geq 1-\sigma
 $$
</div>
<p>那么可以计算出： $e$ 是自然常数</p>
<div>
$$ 
d = [\frac{e}{\epsilon}] , w = [ln(\frac{1}{\sigma})]
 $$
</div>
<p>计算公式来自论文，有效性分析也可以从论文中阅读</p>
<blockquote>
<p>添加一个新哈希函数以指数级别迅速降低超出边界异常数据的概率；当然，增加矩阵的宽度也可以增加减少冲突的概率，但这个只是线性级别。</p>
</blockquote>
<h3 id="count-mean-min-sketch">Count-Mean-Min-Sketch</h3>
<p>由于 Hash 的冲突，CMS 对于低频的元素误差还是太大了，引入噪音对于高频元素可以接受（topk）但是对于低频长尾来说太不准确了，因此有了以下的改进：</p>
<ul>
<li>首先按照 CMS 的流程取出 d 可 sketch</li>
<li>对于每个 hash 估计出一个噪音，噪音为该行的所有整数（除了被查询元素）的平均值</li>
<li>该行的 sketch 减去该行的噪音，作为真正的 sketch</li>
<li>返回 d 个 sketch 的中位数</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">CountMeanMinSketch</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// initialization and addition procedures as in CountMinSketch
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">// n is total number of added elements
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kt">long</span> <span class="nf">estimateFrequency</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kt">long</span> <span class="n">e</span><span class="p">[]</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">long</span><span class="p">[</span><span class="n">d</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span><span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">d</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">sketchCounter</span> <span class="o">=</span> <span class="n">estimators</span><span class="p">[</span><span class="n">i</span><span class="p">][</span> <span class="n">hash</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span> <span class="p">]</span>
</span></span><span class="line"><span class="cl">            <span class="n">noiseEstimation</span> <span class="o">=</span> <span class="p">(</span><span class="n">n</span> <span class="o">-</span> <span class="n">sketchCounter</span><span class="p">)</span> <span class="o">/</span> <span class="p">(</span><span class="n">m</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">e</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">sketchCounter</span> <span class="err">–</span> <span class="n">noiseEstimator</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">median</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>该算法显著改善了在长尾数据上的精确度。</p>
<h2 id="其他解决方式">其他解决方式</h2>
<h3 id="数据分片--hashmap">数据分片 + Hashmap</h3>
<p>假设有 k 台机器，使用以下的方式进行分片后进行 hashmap 的存储，但是这种方式基本上不降低什么存储需求。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">hash</span><span class="p">(</span><span class="n">elem</span><span class="p">)</span> <span class="o">%</span> <span class="n">k</span> <span class="o">=</span> <span class="n">i</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="reference">Reference</h2>
<ul>
<li><a href="https://zhuanlan.zhihu.com/p/140545941" target="_blank" rel="noopener">Bloom Filter</a>
</li>
<li><a href="https://zhuanlan.zhihu.com/p/369981005" target="_blank" rel="noopener">CountMinSketch</a>

<ul>
<li><a href="https://www.cse.unsw.edu.au/~cs9314/07s1/lectures/Lin_CS9314_References/cm-latin.pdf" target="_blank" rel="noopener">Paper</a>
</li>
<li><a href="https://www.youtube.com/watch?v=kx-XDoPjoHw&amp;ab_channel=SystemDesignInterview" target="_blank" rel="noopener">Top K Problem</a>
</li>
<li><a href="https://en.wikipedia.org/wiki/Count%E2%80%93min_sketch" target="_blank" rel="noopener">iwiki</a>
</li>
<li><a href="https://www.youtube.com/watch?v=mPxslXpg8wA&amp;ab_channel=NiemaMoshiri" target="_blank" rel="noopener">Advanced Data Structures: Count-Min Sketches - YouTube</a>
</li>
</ul>
</li>
<li><a href="https://www.liaoxuefeng.com/wiki/1252599548343744/1304227729113121" target="_blank" rel="noopener">Hash</a>
</li>
<li><a href="https://soulmachine.gitbooks.io/system-design/content/cn/bigdata/frequency-estimation.html" target="_blank" rel="noopener">频率估计 System Design</a>
</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Python00 Conda 与 Pip</title>
      <link>https://aikenh.cn/posts/python_pack_manager/</link>
      <pubDate>Mon, 06 Mar 2023 11:27:52 +0000</pubDate>
      <guid>https://aikenh.cn/posts/python_pack_manager/</guid>
      <description>manager python env for development.</description>
      <content:encoded><![CDATA[<p>@Aikenhong 的旧笔记翻新完善 1.0</p>
<p>Python 的灵活和广泛应用场景来自于众多的第三方库，由于强大的可拓展性和众多的库，使得 Python 的使用简单灵活，且应用面极广。</p>
<p>但是不同库之间的相互依赖关系，对版本的不同要求等等因素，使得&quot;环境配置&quot;成为了开发者闻之变色的一词，对一个新的库和项目环境的配置尝尝会花去大量的时间，这可能也是 Docker、Venv（虚拟环境）必须存在的原因之一。</p>
<blockquote>
<p>这里不对 Docker 及其相关技术，进行说明，会另开章节进行学习。</p>
</blockquote>
<p>才疏学浅的本菜鸡希望从 python 开发者避不开的 conda 和 pip 出发介绍一下关于库安装的一些事情，以及这两个 CLI 的关系。</p>
<h2 id="anaconda-miniconda-和-conda">Anaconda MiniConda 和 Conda</h2>
<p>anaconda 是一个针对数据科学的 Python 发行版，其包含了一下三个方面的内容：</p>
<ul>
<li>完整的 python，ipython</li>
<li>numpy、Script 等常用的数据科学库</li>
<li>包管理器 Conda 和 pip</li>
</ul>
<blockquote>
<p>软件发行版是在系统上提前编译和配置好的软件包集合， 装好了后就可以直接用</p>
</blockquote>
<p>miniconda 是 conda 的发行版，其包含了 conda 本体和其所需的所有环境，安装了 miniconda 后就可以正常使用 conda，由于其不包含 python 和诸多第三方包，所以会比 anaconda 纯净得多，我们可以基于其从零开始搭建一个完整的环境。</p>
<p>而 conda 只是一个包（lib、package）和环境（env）的管理工具，其用于自动安装，升级，（也可分析包之间的相互依赖关系）的工具。</p>
<h2 id="conda-和-pip-的关联和区别">Conda 和 Pip 的关联和区别</h2>
<p><strong>conda</strong> 是通用（语言无关且跨平台）的包管理器，它发源于 python 的 pydata 社区，但他不仅适用于 python 包的管理，还适用于任何语言写的包和依赖，但是我们应该大多数时候只用来做 python 管理。</p>
<ul>
<li>其只能在 conda 环境中安装包，但是可以安装各种语言和各种类型的包。</li>
</ul>
<p><strong>pip</strong>（pip install package） 是 python 官方认证的 python 包通用管理器，只能管理 python 包，安装发布于 python package index（pypi）上的所有包，均由 python 官方管理。</p>
<ul>
<li>其支持所有平台，但是只能安装 python 包</li>
</ul>
<p>接下来从一些重要的特性来讲述两者的区别和联系。</p>
<h3 id="虚拟环境支持对比">虚拟环境支持对比</h3>
<p>上述提到，我们希望有一个纯净的开发环境，在配置环境的时候出现诸多冲突，例如：</p>
<blockquote>
<p>PackageA 需要 PackageC&gt;3.11，而 PackageB 需要 PackageC&lt;3.10 导致运行起来冲突，或者无法安装的情况。</p>
</blockquote>
<p>因此我们希望能将每个开发环境隔离起来，项目 A、B、C 有分离的 python 版本和对应的一些 python 库。（这里我把环境简单的理解为 python+python 安装的所有 Package ）</p>
<p>而通过 pip 和 conda 都能在不同程度上，实现以上的需求，conda 原生支持虚拟环境管理，pip 则是需要借助 venv 或者 virtualenv 库来支持。参考：[pip 与 conda 的区别] ( <a href="https://zhuanlan.zhihu.com/p/379321816" target="_blank" rel="noopener">https://zhuanlan.zhihu.com/p/379321816</a>
 )</p>
<table>
  <thead>
      <tr>
          <th>CLI</th>
          <th>Python 版本独立</th>
          <th>Python 依赖（lib）独立</th>
          <th>非 Python 的其他依赖管理</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Conda</td>
          <td>y</td>
          <td>y</td>
          <td>y</td>
      </tr>
      <tr>
          <td>Pip+vir*</td>
          <td>n</td>
          <td>y</td>
          <td>y</td>
      </tr>
  </tbody>
</table>
<blockquote>
<p>python 版本独立的意思是，不同环境之间是不是可以安装不同的 python，pip 只能将依赖分离，而对应的 python 都是同一个。</p>
</blockquote>
<p>可以看出在于包管理上，conda 还是更具优势，主要是因为其本身不需要依赖于某个既有的 python，不需要和该 Python 建立连接，没有沾亲带故的就更铁面无私嘛。具体可以参考上面的链接。</p>
<h3 id="包管理逻辑对比">包管理逻辑对比</h3>
<p>基于上述说明，开发一个 python 项目，我们可以优先创建一个虚拟环境，再在其中安装需要的依赖，这样能保证每一个环境的纯净，也能减少一些不必要的麻烦，也就是说，创建完环境的下一步，就是需要安装和管理每个环境中的包了。</p>
<table>
  <thead>
      <tr>
          <th>CLI</th>
          <th>Source</th>
          <th>依赖校验</th>
          <th>是否需要换源加速/代理</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Conda</td>
          <td>Anaconda &amp; Cloud</td>
          <td>auto(且支持非 python 的依赖)</td>
          <td>狗头</td>
      </tr>
      <tr>
          <td>Pip</td>
          <td>Pypi</td>
          <td>自动检查、手动选择是否</td>
          <td>狗头</td>
      </tr>
  </tbody>
</table>
<p>从上述简单的对比可以看出，两者安装 package 的源不同，这样有以下的两个影响：</p>
<ol>
<li>Conda 最好是添加一些常用的 Channel，添加其软件来源，方便使用 conda 进行包的安装；</li>
<li>即使倾向于使用 conda 做管理，还是会在开发中遇到需要混用 pip 的场景（蛮多） ，那么这样是否会有影响呢？下面我们从两个管理器的安装逻辑来说（结合虚拟环境）：</li>
</ol>
<p><strong>conda 安装包的逻辑</strong>是这样的：</p>
<p>基于 <code>conda install &lt;pkg&gt;</code> 安装的库都会放在 Anaconda 的 Pkgs 目录下统一存储，例如 windows 就是 <code>E:\anaconda\pkgs\&lt;pkg&gt;</code> ，通过这样的方式，当新的环境中需要一个某个环境中<strong>已经安装过的包</strong>的时候，就只需要把对应的文件复制到到新环境的 <code>lib\python&lt;*&gt;\site-packages</code> 目录中即可，无需重复下载。</p>
<blockquote>
<p>anaconda 中会对每个环境创建一个新的目录。而该环境的的库就是存在 <code>、env\&lt;env-name&gt;\lib\pythonxxx\site-packages</code> 路径下。</p>
</blockquote>
<p><strong>pip 安装包的逻辑</strong>是这样的：</p>
<p>基于 <code>pip install &lt;pkg&gt;</code> 安装的库会放在对应的就会放在 <code>xxx\pythonxxx\site-packages</code> 中。</p>
<p><strong>综上所述</strong>，（正常）混用的话基本上是没有影响的，还是能保证我们的环境进行分离，这是因为：</p>
<ul>
<li>当 conda 切换虚拟环境的时候，对应的 pip 也会进行切换，这样通过 pip 安装的包也会仅安装在当前环境的目录中，和 conda 进行安装是一致的</li>
</ul>
<p><strong>同时两者之间还有这样的交互关系：</strong></p>
<ul>
<li><code>conda list</code>  列出的包中，build 项目为 pypi 的即为 pip 安装的包。</li>
<li>卸载的时候两者是一致的： <code>conda uninstall &lt;pkg&gt;</code> 和 <code>pip uninstall &lt;pkg&gt;</code> 都只是讲当前环境中的库删除了，不会删除 conda 的 pkg 目录中的备份，如果要清空该已下载库，通过 <code>conda clean -h</code> 实现</li>
</ul>
<p>（need check）（<strong>not recommand</strong>）理解了这样的安装关系后，我们也可以知道如何为一个环境手动安装一个 package 了，在 pypi 上下载压缩包后，解压到对应的目录中，执行以下命令即可</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">python setup.py install</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>网络问题的话建议换源，还是不要手动安装。</p>
<h2 id="其他相关资料">其他相关资料</h2>
<h3 id="windows-conda-路径问题">windows conda 路径问题</h3>
<ol>
<li>在 windows 上安装 anaconda 之前，如果原本有 python，建议是删掉该 python 避免带来不必要的路径问题。</li>
<li>windows 上如果出现输入 python 跳转 win 商店的话，八成是系统路径中的问题，可以将 winstore 的路径往后挪。</li>
</ol>
<h3 id="pip-和-pip3">pip 和 pip3</h3>
<ul>
<li>python2 只能用 pip</li>
<li>python3 都可以用，如果仅有 python3，那么两者等价</li>
<li>如果装了 python2 和 python3，那么默认 pip 给 python2 用，pip3 给 python3 用，功能一样。</li>
<li>虚拟环境中，若只存在一个 python 版本，可以认为在用系统中 pip 和 pip3 命令都是相同的</li>
</ul>
<h3 id="pip-删除所有安装的包">pip 删除所有安装的包</h3>
<p><a href="https://www.qiniu.com/qfans/qnso-11248073" target="_blank" rel="noopener">删除pip安装的所有软件包的最简单方法是什么？ (qiniu.com)</a>
</p>
]]></content:encoded>
    </item>
    <item>
      <title>Windows Powershell 00 Install and Config</title>
      <link>https://aikenh.cn/posts/powershell/</link>
      <pubDate>Sun, 05 Mar 2023 09:59:40 +0000</pubDate>
      <guid>https://aikenh.cn/posts/powershell/</guid>
      <description>Setup powershell in windows</description>
      <content:encoded><![CDATA[<p>Update:@20230214</p>
<p>shift+右键: 在此处打开 powershell.</p>
<p><a href="https://github.com/PowerShell/PowerShell/releases" target="_blank" rel="noopener">PowerShell </a>
，这里的 PowerShell 和 windows 的已经不是同一个东西了，可能要更先进一些，通过 <code>msi</code> 进行安装，安装完后重启 terminal 就会自动的添加配置，后续的配置在这个 new shell 中进行会更好一些</p>
<h2 id="basic-setting">Basic Setting</h2>
<h3 id="setting--cancel-proxy">Setting &amp; Cancel Proxy</h3>
<p>设置代理如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">netsh</span> <span class="n">winhttp</span> <span class="nb">set </span><span class="n">proxy</span> <span class="mf">127.0</span><span class="p">.</span><span class="py">0</span><span class="p">.</span><span class="mf">1</span><span class="err">:</span><span class="mf">8890</span>
</span></span><span class="line"><span class="cl"><span class="c"># 查看代理设置情况</span>
</span></span><span class="line"><span class="cl"><span class="n">netsh</span> <span class="n">winhttp</span> <span class="n">show</span> <span class="n">proxy</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>取消代理设置使用：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">netsh winhttp reset proxy</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="setting-policy">Setting Policy</h3>
<p>如果 powershell 中禁止运行脚本运行：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 查看当前的策略</span>
</span></span><span class="line"><span class="cl"><span class="nb">get-executionpolicy</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 管理员打开并执行以下命令修改策略</span>
</span></span><span class="line"><span class="cl"><span class="nb">set-executionpolicy</span> <span class="n">remotesigned</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>执行完策略以后就可以安装模块</p>
<h2 id="about-module">About Module</h2>
<p><a href="https://learn.microsoft.com/zh-cn/powershell/module/microsoft.powershell.core/about/about_modules?view=powershell-7.3" target="_blank" rel="noopener">关于模块 - PowerShell | Microsoft Learn</a>
 模块是包含了 Powershell 命令，函数，工作流，变量或者别名的包，打包作为一个整体来提供和加载，便于共享使用。可以作为 powershell 的 “插件”或者拓展功能来理解他。</p>
<blockquote>
<p><strong>模块自动加载</strong>的新功能占位，目前还没有很理解。</p>
</blockquote>
<p><code>get-module</code> 可以查看当前会话已经加载的模块，我们也可以通过 <code>get-module -ListAvailable</code> 列出所有可供加载的模块（已安装）</p>
<p><strong>如何安装模块</strong>（上述参考链接中提供了迁移模块目录的方法）：</p>
<p><code>Install-Module</code> 命令可以从联机存储库获取符合指定条件的模块，并将其安装到默认的模块安装地址。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">install-module</span> <span class="n">-name</span> <span class="n">-dirColors</span> <span class="n">-verbose</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>该命令有许多参数，这里主要推荐 <code>-scope</code> 指定安装用户，<code>-name</code> 指定搜索的包名，<code>-verbose</code> 可视化安装过程，便于 Check 是否卡住（可以用 <code>get-module</code> 命令来检查是否安装完成）</p>
<p>其他的参数可以参考官方链接： <a href="https://learn.microsoft.com/zh-cn/powershell/module/powershellget/install-module?view=powershell-7.3" target="_blank" rel="noopener">Install-Module (PowerShellGet) - PowerShell | Microsoft Learn</a>
，包括安装指定版本，查找结合安装等等。</p>
<p>在完成 module 的安装过后，我们需要将该模块导入会话，类似 <code>import</code> 之于 python，也可以借助 <code>$PROFILE</code> 默认导入每一个会话。那么</p>
<p><strong>如何导入模块</strong>：使用 <code>Import-Module</code>，<strong>导入模块</strong> 到当前会话，也可以将导入命令写到配置文件中，使其默认导入每一个新开的会话中，配置文件我们可以通过如下的方法进行编辑</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">echo </span><span class="nv">$PROFILE</span> <span class="c"># 找到配置文件的目录，使用自己喜欢的编辑器进行编辑。</span>
</span></span><span class="line"><span class="cl"><span class="n">vim</span> <span class="nv">$PROFILE</span> <span class="c"># 或者使用 vim 在这里直接编辑，我这里使用的是 vscode，将 vim 换成 code 也一样。</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>其他一些关于配置文件的操作和用法展示可以参考： <a href="https://learn.microsoft.com/zh-cn/powershell/module/microsoft.powershell.core/about/about_profiles?view=powershell-7.3" target="_blank" rel="noopener">关于配置文件 - PowerShell | Microsoft Learn</a>
，在后续介绍了特定模块的安装之后，我将会展示一个对应的配置文件例子。</p>
<p><strong>如何卸载&amp;取消导入模块</strong>：</p>
<p>当我们不希望载入部分模块或者觉得一些模块是鸡肋的时候，可以通过 <code>remove-module</code> 命令取消该模块在当前会话中的加载，或者通过 <code>Uninstall-Module -name </code> 命令直接将该模块删除，这里需要注意的是，有些模块的 Uninstall 可能不会立即生效，这个时候我们可以重启会话看是否已经卸载。</p>
<p>在对模块的定义和模块的一些操作有了基本的了解之后，接下来我们通过安装一些模块来美化&amp;优化 Powershell 使其在更好看的同时也更好用。</p>
<h2 id="install-module">Install Module</h2>
<h3 id="install-psreadline--config-it">Install PSReadLine &amp; config it</h3>
<p>新版的 Powershell 会默认安装 PSReadLine，没有默认安装 PSReadLine 模块的话：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">Install-Module</span> <span class="n">-name</span> <span class="n">PSReadLine</span> <span class="n">-verbose</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>也可以按照下面的流程，安装 PowerShell 插件：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 后面的这些User的限制倒是不需要</span>
</span></span><span class="line"><span class="cl"><span class="c"># 安装PSReadLine</span>
</span></span><span class="line"><span class="cl"><span class="nb">Install-Module</span> <span class="n">-Name</span> <span class="n">PSReadLine</span>  <span class="n">-Scope</span> <span class="n">CurrentUser</span>
</span></span><span class="line"><span class="cl"><span class="c"># 如果上面安装出现问题, 可以尝试下面的</span>
</span></span><span class="line"><span class="cl"><span class="nb">Install-Module</span> <span class="n">-Name</span> <span class="n">PSReadLine</span> <span class="n">-Scope</span> <span class="n">CurrentUser</span> <span class="n">-Force</span> <span class="n">-SkipPublisherCheck</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 安装PSR包，让命令行更好用，类似ZSH</span>
</span></span><span class="line"><span class="cl"><span class="nb">Install-Module</span> <span class="n">-Name</span> <span class="n">PSReadLine</span>
</span></span><span class="line"><span class="cl"><span class="nb">Install-Module</span> <span class="n">-Name</span> <span class="n">PSReadLine</span> <span class="n">-Scope</span> <span class="n">CurrentUser</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 查看是否安装完成</span>
</span></span><span class="line"><span class="cl"><span class="nb">Get-Module</span> <span class="n">-ListAvailable</span>
</span></span><span class="line"><span class="cl"><span class="nb">Import-Module</span> <span class="n">PSReadLine</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 安装Posh-git包，让git更好用</span>
</span></span><span class="line"><span class="cl"><span class="nb">Install-Module</span> <span class="n">-Name</span> <span class="nb">posh-git</span>
</span></span><span class="line"><span class="cl"><span class="nb">Install-Module</span> <span class="n">-Name</span> <span class="nb">posh-git</span> <span class="n">-Scope</span> <span class="n">CurrentUser</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以在会话中 Import 测试效果，并将满意的配置写入 <code>$PROFILE</code>。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">Import-Module</span> <span class="n">PSReadLine</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>设置 PSReadLine 将以下的内容写入 PROFILE （或者逐一在会话中执行验证效果）：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 设置预测文本来源为历史记录</span>
</span></span><span class="line"><span class="cl"><span class="nb">Set-PSReadLineOption</span> <span class="n">-PredictionSource</span> <span class="nb">History
</span></span></span><span class="line"><span class="cl"><span class="nb"></span>
</span></span><span class="line"><span class="cl"><span class="c"># 每次回溯输入历史，光标定位于输入内容末尾</span>
</span></span><span class="line"><span class="cl"><span class="nb">Set-PSReadLineOption</span> <span class="n">-HistorySearchCursorMovesToEnd</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 设置 Tab 为菜单补全和 Intellisense</span>
</span></span><span class="line"><span class="cl"><span class="nb">Set-PSReadLineKeyHandler</span> <span class="n">-Key</span> <span class="s2">&#34;Tab&#34;</span> <span class="n">-Function</span> <span class="n">MenuComplete</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 设置 Ctrl+d 为退出 PowerShell</span>
</span></span><span class="line"><span class="cl"><span class="nb">Set-PSReadlineKeyHandler</span> <span class="n">-Key</span> <span class="s2">&#34;Ctrl+d&#34;</span> <span class="n">-Function</span> <span class="n">ViExit</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 设置 Ctrl+z 为撤销</span>
</span></span><span class="line"><span class="cl"><span class="nb">Set-PSReadLineKeyHandler</span> <span class="n">-Key</span> <span class="s2">&#34;Ctrl+z&#34;</span> <span class="n">-Function</span> <span class="n">Undo</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 设置向上键为后向搜索历史记录</span>
</span></span><span class="line"><span class="cl"><span class="nb">Set-PSReadLineKeyHandler</span> <span class="n">-Key</span> <span class="n">UpArrow</span> <span class="n">-Function</span> <span class="n">HistorySearchBackward</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 设置向下键为前向搜索历史纪录</span>
</span></span><span class="line"><span class="cl"><span class="nb">Set-PSReadLineKeyHandler</span> <span class="n">-Key</span> <span class="n">DownArrow</span> <span class="n">-Function</span> <span class="n">HistorySearchForward</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>完成设置后 PSReadLine 会基于历史记录对已输入的命令进行补全。</p>
<h3 id="install-posh-git-and-oh-my-posh">Install Posh-git and Oh-My-Posh</h3>
<p><a href="https://ohmyposh.dev/docs/installation/windows" target="_blank" rel="noopener">Windows | Oh My Posh</a>
，posh-git 可以强化 omp 的 git 的表现，首先安装两个包。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">Install-Module</span> <span class="n">-name</span> <span class="nb">posh-git</span>
</span></span><span class="line"><span class="cl"><span class="n">winget</span> <span class="n">install</span> <span class="n">JanDeDobbeleer</span><span class="p">.</span><span class="py">OhMyPosh</span> <span class="n">-s</span> <span class="n">winget</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>安装完进行导入：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">oh-my</span><span class="n">-posh</span> <span class="n">init</span> <span class="n">pwsh</span> <span class="p">|</span> <span class="nb">Invoke-Expression</span>
</span></span><span class="line"><span class="cl"><span class="nb">Import-Module</span> <span class="nb">posh-git</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>完成安装  <code>oh-my-posh</code> 后，重启 Terminal，然后查看存在的主题，并设置为你希望的主题，将后面的 jandedobbeleer 改成需要的主题名称（后续写入 PROFILE）。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">Get-PoshThemes</span>
</span></span><span class="line"><span class="cl"><span class="nb">oh-my</span><span class="n">-posh</span> <span class="n">init</span> <span class="n">pwsh</span> <span class="p">-</span><span class="n">-config</span> <span class="s1">&#39;C:\Users\Aiken\AppData\Local\Programs\oh-my-posh\themes\jandedobbeleer.omp.json&#39;</span> <span class="p">|</span> <span class="nb">Invoke-Expression</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>字体安装与下载：按照<a href="https://www.nerdfonts.com/font-downloads" target="_blank" rel="noopener">链接</a>
下载安装就行了</p>
<h3 id="install-scoop">Install Scoop</h3>
<p><a href="https://github.com/ScoopInstaller/Install#readme" target="_blank" rel="noopener">ScoopInstaller/Install: 📥 Next-generation Scoop (un)installer (github.com)</a>

<a href="https://drrany.github.io/wt/#%E6%B7%BB%E5%8A%A0%E4%BB%93%E5%BA%93" target="_blank" rel="noopener">Windows Terminal美化（配置Powershell7+PSReadLine+oh-my-posh） / Drrany</a>

<a href="https://sspai.com/post/65933" target="_blank" rel="noopener">Windows 系统缺失的包管理器：Chocolatey、WinGet 和 Scoop - 少数派 (sspai.com)</a>
</p>
<p>安装 Scoop 的话只需要执行：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">irm </span><span class="n">get</span><span class="p">.</span><span class="py">scoop</span><span class="p">.</span><span class="py">sh</span> <span class="p">|</span> <span class="n">iex</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>Scoop 的默认安装位置为：<code>C:\User\Your Username\scoop</code>，(option) 如果需要将其安装在默认目录以外的地方的话，执行：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nv">$env:SCOOP</span><span class="p">=</span><span class="s1">&#39;D:\Applications\Scoop&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$env:SCOOP_GLOBAL</span><span class="p">=</span><span class="s1">&#39;D:\GlobalScoopApps&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="no">Environment</span><span class="p">]::</span><span class="n">SetEnvironmentVariable</span><span class="p">(</span><span class="s1">&#39;SCOOP_GLOBAL&#39;</span><span class="p">,</span> <span class="nv">$env:SCOOP_GLOBAL</span><span class="p">,</span> <span class="s1">&#39;User&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">irm </span><span class="n">get</span><span class="p">.</span><span class="py">scoop</span><span class="p">.</span><span class="py">sh</span> <span class="p">|</span> <span class="n">iex</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>安装完毕后即可，安装个 neofetch 试试：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">scoop</span> <span class="n">install</span> <span class="n">neofetch</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>Scoop 会自动将 <code>&lt;install_path&gt;\Scoop\shims</code> and <code>&lt;install_path&gt;\Scoop\apps</code> 加入系统的环境变量，免去自行添加的麻烦。</p>
<p>Scoop 设置/取消代理：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">scoop</span> <span class="n">config</span> <span class="n">proxy</span> <span class="mf">127.0</span><span class="p">.</span><span class="py">0</span><span class="p">.</span><span class="mf">1</span><span class="err">:</span><span class="mf">8889</span>
</span></span><span class="line"><span class="cl"><span class="n">scoop</span> <span class="n">config</span> <span class="nb">rm </span><span class="n">proxy</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>添加 bucket 等操作之后再 Scoop 章节中介绍</strong></p>
<ul>
<li>安装 sudo</li>
<li>安装 curl</li>
<li>安装 wget （代理使用 powershell 的代理）</li>
</ul>
<h3 id="install-other-module">Install other module</h3>
<p>高亮 ls 的文件夹(DirColors )并添加文件图标（Terminal-Icons）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">Install-Module</span> <span class="n">-Name</span> <span class="n">DirColors</span>
</span></span><span class="line"><span class="cl"><span class="nb">Install-Module</span> <span class="n">-Name</span> <span class="nb">Terminal-Icons</span>
</span></span><span class="line"><span class="cl"><span class="nb">Import-Module</span> <span class="n">DirColors</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>安装 z-jumper</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">Install-Module</span> <span class="n">ZLocation</span> <span class="n">-Scope</span> <span class="n">CurrentUser</span>
</span></span><span class="line"><span class="cl"><span class="nb">import-module</span> <span class="n">zlocation</span>
</span></span><span class="line"><span class="cl"><span class="n">z</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>查看现存主题：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">Get-PoshThemes</span>
</span></span><span class="line"><span class="cl"><span class="c"># 设置主题</span>
</span></span><span class="line"><span class="cl"><span class="nb">Set-PoshPrompt</span> <span class="n">-Theme</span> <span class="nb">half-life</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>设置 Terminal 中的启动参数</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">code</span> <span class="nv">$PROFILE</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>并设置成如下的形式</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 导入包</span>
</span></span><span class="line"><span class="cl"><span class="nb">Import-Module</span> <span class="nb">posh-git</span>
</span></span><span class="line"><span class="cl"><span class="nb">Import-Module</span> <span class="nb">oh-my</span><span class="n">-posh</span>
</span></span><span class="line"><span class="cl"><span class="nb">oh-my</span><span class="n">-posh</span> <span class="n">init</span> <span class="n">pwsh</span> <span class="p">|</span> <span class="nb">Invoke-Expression</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">Import-Module</span> <span class="n">PSReadLine</span>
</span></span><span class="line"><span class="cl"><span class="c"># 设置主题</span>
</span></span><span class="line"><span class="cl"><span class="nb">Set-PoshPrompt</span> <span class="n">-Theme</span> <span class="n">spaceship</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># ================psreadline setting</span>
</span></span><span class="line"><span class="cl"><span class="c"># 设置预测文本来源为历史记录</span>
</span></span><span class="line"><span class="cl"><span class="nb">Set-PSReadLineOption</span> <span class="n">-PredictionSource</span> <span class="nb">History
</span></span></span><span class="line"><span class="cl"><span class="nb"></span><span class="c"># 每次回溯输入历史，光标定位于输入内容末尾</span>
</span></span><span class="line"><span class="cl"><span class="nb">Set-PSReadLineOption</span> <span class="n">-HistorySearchCursorMovesToEnd</span>
</span></span><span class="line"><span class="cl"><span class="c"># 设置 Tab 为菜单补全和 Intellisense</span>
</span></span><span class="line"><span class="cl"><span class="nb">Set-PSReadLineKeyHandler</span> <span class="n">-Key</span> <span class="s2">&#34;Tab&#34;</span> <span class="n">-Function</span> <span class="n">MenuComplete</span>
</span></span><span class="line"><span class="cl"><span class="c"># 设置 Ctrl+d 为退出 PowerShell</span>
</span></span><span class="line"><span class="cl"><span class="nb">Set-PSReadlineKeyHandler</span> <span class="n">-Key</span> <span class="s2">&#34;Ctrl+d&#34;</span> <span class="n">-Function</span> <span class="n">ViExit</span>
</span></span><span class="line"><span class="cl"><span class="c"># 设置 Ctrl+z 为撤销</span>
</span></span><span class="line"><span class="cl"><span class="nb">Set-PSReadLineKeyHandler</span> <span class="n">-Key</span> <span class="s2">&#34;Ctrl+z&#34;</span> <span class="n">-Function</span> <span class="n">Undo</span>
</span></span><span class="line"><span class="cl"><span class="c"># 设置向上键为后向搜索历史记录</span>
</span></span><span class="line"><span class="cl"><span class="nb">Set-PSReadLineKeyHandler</span> <span class="n">-Key</span> <span class="n">UpArrow</span> <span class="n">-Function</span> <span class="n">HistorySearchBackward</span>
</span></span><span class="line"><span class="cl"><span class="c"># 设置向下键为前向搜索历史纪录</span>
</span></span><span class="line"><span class="cl"><span class="nb">Set-PSReadLineKeyHandler</span> <span class="n">-Key</span> <span class="n">DownArrow</span> <span class="n">-Function</span> <span class="n">HistorySearchForward</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="some-command">Some Command</h2>
<h3 id="findstrfind">Findstr/Find</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># this command is like grep in Linux</span>
</span></span><span class="line"><span class="cl"><span class="nb">Common-u</span><span class="n">-want-to-carry-out</span> <span class="p">|</span> <span class="n">findStr</span> <span class="s2">&#34;String&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c"># for example</span>
</span></span><span class="line"><span class="cl"><span class="n">conda</span> <span class="n">list</span> <span class="p">|</span> <span class="nb">Select-String</span> <span class="p">(</span><span class="s2">&#34;matplot&#34;</span> <span class="p">,</span> <span class="s2">&#34;pillow&#34;</span><span class="p">,</span> <span class="s2">&#34;scipy&#34;</span><span class="p">,</span> <span class="s2">&#34;tensorboard&#34;</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="generate-guid">Generate GUID</h3>
<p>this command can generate the only GUID</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">new-guid</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="reference">reference</h2>
<ol>
<li>个人的知乎回答</li>
<li><a href="https://medium.com/@hjgraca/style-your-windows-terminal-and-wsl2-like-a-pro-9a2e1ad4c9d0" target="_blank" rel="noopener">Style your Windows terminal</a>
</li>
<li><a href="https://zhuanlan.zhihu.com/p/137595941" target="_blank" rel="noopener">Windows Terminal 完美配置 </a>
</li>
<li><a href="https://ohmyposh.dev/docs/upgrading" target="_blank" rel="noopener">Upgrading | Oh My Posh</a>
</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>Bash Notebook 01</title>
      <link>https://aikenh.cn/posts/shell/</link>
      <pubDate>Wed, 25 Jan 2023 22:04:15 +0000</pubDate>
      <guid>https://aikenh.cn/posts/shell/</guid>
      <description>How to write shell script.</description>
      <content:encoded><![CDATA[<p>整理脚本编写的一些最基本语法，包括参数传递，赋值，循环等基本语句，方便后续的脚本编写和改动。</p>
<h2 id="语句注释">语句注释</h2>
<p>单行注释：<code>#</code> ，多行注释：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">:<span class="s1">&#39;
</span></span></span><span class="line"><span class="cl"><span class="s1">多行注释用冒号加单引号即可
</span></span></span><span class="line"><span class="cl"><span class="s1">&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;legal&#39;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="命令行参数传递">命令行参数传递</h2>
<p>命令行传递参数的方式极其简单，<code> $1</code> &hellip; <code>$ 9</code> 可分别代表输入的 9 个参数，第 10 个参数则使用 <code>${10}</code> 表示，可以将其赋予变量后便于使用。</p>
<p>一些特殊参数：</p>
<ol>
<li><code>$0</code> 脚本本身的名称</li>
<li><code>$#</code> 输入参数的数量</li>
<li><code>$$</code> 进程 ID</li>
<li><code> $*</code> | <code>$ @</code> 所有参数（从第一个开始</li>
<li><code>$(PWD)</code> | `pwd` 都能输出当前的工作路径</li>
</ol>
<p>举个脚本例子如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># we accept args from commandline and print it to the screen</span>
</span></span><span class="line"><span class="cl"><span class="c1"># define</span>
</span></span><span class="line"><span class="cl"><span class="nv">args1</span><span class="o">=</span><span class="nv">$1</span>
</span></span><span class="line"><span class="cl"><span class="nv">args2</span><span class="o">=</span><span class="nv">$2</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># print</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;using </span>$<span class="s2"> { } to get the value of val, what we receive is : </span><span class="si">${</span><span class="nv">args1</span><span class="si">}</span><span class="s2"> and </span><span class="si">${</span><span class="nv">args2</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;</span>$<span class="s2"> can also show : </span><span class="nv">$args1</span><span class="s2"> and </span><span class="nv">$args2</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># we can make those statement in a string, which may transfer to its value</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;using </span>$<span class="s2"> / {} in a string can also get the value like </span><span class="nv">$args1</span><span class="s2"> and </span><span class="nv">$args2</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;using $ / {} in a string single quotes cannot get the value like $args1 and $args2&#39;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>一些特殊的参数，用来描述基础信息如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># basic infomation of script.</span>
</span></span><span class="line"><span class="cl"><span class="nv">name_of_script</span><span class="o">=</span><span class="nv">$0</span>
</span></span><span class="line"><span class="cl"><span class="nv">num_of_args</span><span class="o">=</span><span class="nv">$#</span>
</span></span><span class="line"><span class="cl"><span class="nv">PID</span><span class="o">=</span><span class="nv">$$</span>
</span></span><span class="line"><span class="cl"><span class="nv">args_list</span><span class="o">=</span><span class="nv">$*</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;the name of this script is </span><span class="si">${</span><span class="nv">name_of_script</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;we have </span><span class="si">${</span><span class="nv">num_of_args</span><span class="si">}</span><span class="s2"> args&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;and this process&#39; ID is </span><span class="nv">$PID</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$args_list</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$@</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">PWD</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;`pwd`&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="基本数据类型">基本数据类型</h2>
<p><strong>数组和字符串的通用操作</strong>：切片方法<code>${name:位置:长度}</code>，位置可以取负值，0的话也可以省略成冒号</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230129143456.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230129143456.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230129143456.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="数组">数组</h3>
<p><strong>数组的定义</strong>基本规则是：用（）定义数组，用 SPC 区分元素。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">Fruits_Array</span><span class="o">=(</span><span class="s1">&#39;apple&#39;</span> <span class="s1">&#39;banana&#39;</span> <span class="s1">&#39;ogange&#39;</span><span class="o">)</span>
</span></span><span class="line"><span class="cl"><span class="nv">Array1</span><span class="o">=({</span>A..D<span class="o">})</span> <span class="c1"># =&gt; A B C D</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>还可以<strong>使用<a href="https://linuxhint.com/bash_declare_command/" target="_blank" rel="noopener">声明</a>
的方式构造</strong>数组：</p>
<blockquote>
<p>Bash 的变量定义可以不需要指定类型，但是声明的方式，可以在定义的同时指定变量的类型，其中参数列表可以参考跳转链接。</p>
</blockquote>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">declare</span> -a <span class="nv">Numbers</span><span class="o">=(</span><span class="m">1</span> <span class="m">2</span> 3<span class="o">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 不支持{}的方式构造，会只剩下最后一个元素，这个问题还需要深究。</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>数组的调用</strong>和大部分语言一样使用 <code>[]</code> 结合索引来调用其中的元素，元素的索引从 0 开始，同时在使用 echo 等特殊情况下，调用数组的时候，由于 <code>[]</code> 的存在所以要使用 <code> ${}</code> 来引用。不能只是用 <code>$ </code></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="nv">Array1</span><span class="p">[0]</span><span class="si">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>Append 操作</strong>支持使用 <code>+=</code> 实现数组的延伸，如下所示：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">Array1</span><span class="o">+=(</span><span class="m">2</span> 3<span class="o">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>数组的拼接、添加、删除等操作</strong>，其中拼接，添加等操作存在一致性，从文件中获取数组的方式更是一个比较实用的命令，但是注意能不能自动识别其中的分隔符，或者自定义呢？</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">Array2</span><span class="o">=(</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">Array1</span><span class="p">[@]</span><span class="si">}</span><span class="s2">&#34;</span> <span class="s2">&#34;New Element&#34;</span><span class="o">)</span> 
</span></span><span class="line"><span class="cl"><span class="c1"># 如果不添加的话也可以用作赋值，同样也可以用这样的方式连接两个数组。</span>
</span></span><span class="line"><span class="cl"><span class="nv">Array1</span><span class="o">+=(</span><span class="s2">&#34;new element&#34;</span><span class="o">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 通过正则表达式删除的方法暂时还没掌握，占位。</span>
</span></span><span class="line"><span class="cl">unser Array1<span class="o">[</span>2<span class="o">]</span> <span class="c1"># 删除一项</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 从文件中获取数组</span>
</span></span><span class="line"><span class="cl"><span class="nv">Lines</span><span class="o">=(</span><span class="sb">`</span>cat <span class="s2">&#34;logfile&#34;</span><span class="sb">`</span><span class="o">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>数组的快速索引列表：便于调用或者分析数组的状态，其中范围的用法暂时比较不明确，暂时不使用，后续进行补充。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230128131402.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230128131402.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230128131402.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="字符串">字符串</h3>
<p>在大多语言中，对字符串的操作和数组的操作都会有很多的共通性，同样在bash中也是如此，例如切片之类的行为都和数组是一致的，在这里我们基于独有的共通的来描述。</p>
<p><strong>字符串定义</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">name</span><span class="o">=</span><span class="s2">&#34;AikenHong.bash&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>字符串操作</strong></p>
<ol>
<li>删除第一个匹配(前缀)的字符串&quot;suffix&quot;</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="nv">name</span><span class="p">%bash</span><span class="si">}</span> <span class="c1"># 会输出AikenHong.</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="2">
<li>删除最后一个匹配（后缀）的字符串&quot;prefix&quot;</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="nv">name</span><span class="p">#AikenHong</span><span class="si">}</span> <span class="c1"># 会输出.bash</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="3">
<li>删除（长后缀）<code>%%</code>，和删除（长前缀）<code>##</code>和非长版本的区别如下，实际上可以理解为删除第一个匹配到的或者最后一个匹配到的，长的版本最好是使用通配符来使用比较好理解。</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">name2</span><span class="o">=</span><span class="s2">&#34;aikenhong.github.bash.aikenhong&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="nv">name2</span><span class="p">%%.*</span><span class="si">}</span> <span class="c1"># 输出aikenhong</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="nv">name2</span><span class="p">%.*</span><span class="si">}</span> <span class="c1"># 输出aikenhong.github.bash</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="nv">name2</span><span class="p"># *.</span><span class="si">}</span> <span class="c1"># 输出github.bash.aikenhong</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="nv">name2</span><span class="p">## *.</span><span class="si">}</span> <span class="c1"># 输出 aikenhong</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>只要记住前缀后缀删除的关键命令分别是<code>#</code>和<code>%</code>即可，同理，替换的关键词是<code>/from/to</code>和<code>//from(all)/to</code>一个代表替换第一个，一个代表替换所有。</p>
<ol start="4">
<li>替换命令</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="nv">name</span><span class="p">/AikenHong/Metis</span><span class="si">}</span> <span class="c1"># 会输出metis.bash</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>全部替换的话</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="nv">name</span><span class="p">//n/i</span><span class="si">}</span> <span class="c1"># 会输出aikeihoig.bash</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="5">
<li>大小写切换，切换大写使用<code>^</code>，切换小写使用<code>,</code>，全部切换使用<code>,,</code>或<code>^^</code>，或使用<code>foo[@],</code>和<code>foo[@]^^</code></li>
</ol>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230129143543.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230129143543.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230129143543.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><strong>字符串的路径处理</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">SRC</span><span class="o">=</span><span class="s2">&#34;/path/to/foo.cpp&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">BASEPATH</span><span class="o">=</span><span class="si">${</span><span class="nv">SRC</span><span class="p">##*/</span><span class="si">}</span>   
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="nv">$BASEPATH</span>  <span class="c1"># =&gt; &#34;foo.cpp&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">DIRPATH</span><span class="o">=</span><span class="si">${</span><span class="nv">SRC</span><span class="p">%</span><span class="nv">$BASEPATH</span><span class="si">}</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="nv">$DIRPATH</span>   <span class="c1"># =&gt; &#34;/path/to/&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="字典">字典</h3>
<blockquote>
<p>bash 对字典的支持是后续引入的，如果 bash 在旧的版本可能会出现 declare -A 参数无效的问题。</p>
</blockquote>
<p>字典类型有点像是原生之外拓展的类型，只能用 declare 来进行声明，声明后的定义方式借助数组，下面举个例子：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">declare</span> -A myDict</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>接着给字典赋值，一种是用来赋初值，另一种是动态赋值方法：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">myDict</span><span class="o">=([</span>key1<span class="o">]=</span><span class="s2">&#34;value1&#34;</span> <span class="o">[</span>key2<span class="o">]=</span><span class="s2">&#34;value2&#34;</span> <span class="o">[</span>key3<span class="o">]=</span><span class="s2">&#34;value3&#34;</span><span class="o">)</span>
</span></span><span class="line"><span class="cl">myDict<span class="o">[</span><span class="s1">&#39;key&#39;</span><span class="o">]=</span>value</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>调用变量进行打印的时候参照定义数组的方式：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="nv">myDict</span><span class="p">[key1]</span><span class="si">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>其他的一些常见索引，和数组是类似的，但是注意的是！输出的是 key，默认的输出的是 value：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230128141227.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230128141227.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230128141227.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>字典的拼接好像没有很方便，建议是使用循环来进行复制实现复制。</p>
<h2 id="基础运算符">基础运算符</h2>
<ul>
<li><input disabled="" type="checkbox"> 这里还需要搞清楚两个括号和一个括号的区别˙
<a href="https://www.cnblogs.com/zeweiwu/p/5485711.html" target="_blank" rel="noopener">Shell 中test 单中括号[] 双中括号的区别</a>
</li>
</ul>
<h3 id="与或非">与或非</h3>
<ul>
<li><code>[[ ! EXPR ]]</code> ：Not</li>
<li><code>[[ X &amp;&amp; Y ]]</code>  | <code>[ -a ]</code> ：And</li>
<li><code>[[ X || Y ]]</code>  | <code>[-o ]</code> ：Or</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[</span> <span class="s2">&#34;</span><span class="nv">$1</span><span class="s2">&#34;</span> <span class="o">=</span> <span class="s1">&#39;y&#39;</span> -a <span class="nv">$2</span> -gt <span class="m">0</span> <span class="o">]</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl">	<span class="k">then</span> <span class="nb">echo</span> <span class="s2">&#34;yes&#34;</span> 
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[[</span> X <span class="o">&amp;&amp;</span> Y <span class="o">]]</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl">	<span class="k">then</span> ... 
</span></span><span class="line"><span class="cl"><span class="k">fi</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="数字比较运算符">数字比较运算符</h3>
<p>用于 <code>[[]]</code> 的比较运算符如下</p>
<ul>
<li><code>-eq</code> | <code>-ne</code> ：（equal）等于 &amp; 不等于</li>
<li><code>-lt</code> | <code>-le</code> ：（less than）小于 &amp; 小于等于（less or equal）</li>
<li><code>-gt</code> | <code>-ge</code> ：（greater than）大于 &amp; 大于等于</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="o">[[</span> NUM -eq NUM <span class="o">]]</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>用于 <code>(())</code> 情况下的比较运算符</p>
<ul>
<li><code>&lt;</code> | <code>&lt;=</code> | <code>&gt;</code> | <code>&gt;=</code></li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="o">(</span> NUM &lt; NUM <span class="o">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="字符串比较运算符">字符串比较运算符</h3>
<ul>
<li><code>[[ -z STR ]]</code> ：空字符串</li>
<li><code>[[ -n STR ]]</code> ：非空字符串</li>
<li><code>[[ STR == STR ]]</code>  | <code>[[ STR = STR ]]</code> | <code>[[ STR != STR]]</code> ：相等 | 不相等</li>
<li><code>[[ STR &lt; STR ]]</code> |  <code>[[ STR &gt; STR ]]</code>  ：基于 ASCII 的大于小于</li>
<li><code>[[ STR =~ re ]]</code> ：正则表达式（re）</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[[</span> -z <span class="s2">&#34;</span><span class="nv">$string</span><span class="s2">&#34;</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">	<span class="nb">echo</span> <span class="s2">&#34;String is empty&#34;</span> 
</span></span><span class="line"><span class="cl"><span class="k">elif</span> <span class="o">[[</span> -n <span class="s2">&#34;</span><span class="nv">$string</span><span class="s2">&#34;</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">	<span class="nb">echo</span> <span class="s2">&#34;String is not empty&#34;</span> 
</span></span><span class="line"><span class="cl"><span class="k">else</span> 
</span></span><span class="line"><span class="cl">	<span class="nb">echo</span> <span class="s2">&#34;This never happens&#34;</span> 
</span></span><span class="line"><span class="cl"><span class="k">fi</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="文件比较运算符">文件比较运算符</h3>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230125181208.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230125181208.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230125181208.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="循环语句">循环语句</h2>
<p>Shell 中的循环语句主要分为以下的几种，for | while | until 模式，以循环输出数字给出例子。for 和 while 和其他语言中的一致，until 为当条件不满足的时候一直进入循环，直到满足条件的时候退出循环（和 while 相反）</p>
<p>在描述循环之前，先解释一下<strong>生成序列</strong>的一些方法(下面都能生成 1 到 n 的序列)，就像range:</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">seq <span class="m">1</span> n <span class="p">|</span> seq <span class="m">1</span> step n
</span></span><span class="line"><span class="cl"><span class="o">{</span>1..n<span class="o">}</span> <span class="p">|</span> <span class="o">{</span>1..n..step<span class="o">}</span>
</span></span><span class="line"><span class="cl"><span class="s2">&#34;a b c d&#34;</span> <span class="c1"># 会产生 a b c d 的序列</span>
</span></span><span class="line"><span class="cl">‘word1’ ‘word2’ <span class="c1"># 也会产生相应的序列</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li><code>break</code> 和 <code>Continue</code> 的用法和其他语言中的是一致的，这里不再赘述。</li>
</ul>
<h3 id="for-循环">for 循环</h3>
<p><strong>for &hellip; in &hellip; 模式</strong>： 和 python 类似，针对任何类型的列表进行循环，可以结合上述的序列生成方法进行循环。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;using seq to generate list&#39;</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> i in <span class="sb">`</span>seq <span class="m">1</span> 3<span class="sb">`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">do</span>
</span></span><span class="line"><span class="cl">	<span class="nb">echo</span> <span class="nv">$i</span>
</span></span><span class="line"><span class="cl"><span class="k">done</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">for</span> i in <span class="k">$(</span>seq <span class="m">1</span> 3<span class="k">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">do</span>
</span></span><span class="line"><span class="cl">	<span class="nb">echo</span> <span class="nv">$i</span>
</span></span><span class="line"><span class="cl"><span class="k">done</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;using {...} to generate list&#39;</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> i in <span class="o">{</span>1..3<span class="o">}</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">do</span>
</span></span><span class="line"><span class="cl">	<span class="nb">echo</span> <span class="nv">$i</span>
</span></span><span class="line"><span class="cl"><span class="k">done</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>c 模式</strong>：类似 c 语言系列的 for 循环，相比于 list 相对灵活一些，较好构造。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="k">for</span> <span class="o">((</span><span class="nv">i</span><span class="o">=</span>0<span class="p">;</span>i&lt;3<span class="p">;</span><span class="nv">i</span><span class="o">+=</span>2<span class="o">))</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">do</span>
</span></span><span class="line"><span class="cl">	<span class="nb">echo</span> <span class="nv">$i</span>
</span></span><span class="line"><span class="cl"><span class="k">done</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>利用 for 循环遍历文件</strong>：和*一起使用可以方便的遍历文件，算是 for 循环的一个优势。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="k">for</span> i in *.sh<span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">	<span class="nb">echo</span> <span class="nv">$i</span>
</span></span><span class="line"><span class="cl"><span class="k">done</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">for</span> i in /etc/rc.*<span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">	<span class="nb">echo</span> <span class="nv">$i</span>
</span></span><span class="line"><span class="cl"><span class="k">done</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>需要注意的事</strong>：如果 do 和循环同行的话就需要分号，如果执行了换行就不需要分号了。</p>
<h3 id="while-循环">while 循环</h3>
<p>当条件满足的时候进入循环，用法如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">i</span><span class="o">=</span><span class="m">3</span>
</span></span><span class="line"><span class="cl"><span class="k">while</span> <span class="o">[[</span> <span class="nv">$i</span> -gt <span class="m">0</span> <span class="o">]]</span><span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">	<span class="nb">echo</span> <span class="s2">&#34;Number: </span><span class="nv">$i</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="o">((</span>i--<span class="o">))</span>
</span></span><span class="line"><span class="cl"><span class="k">done</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>典型的用法就是用来读取文件，这种时候可以通过管道命令来使用 while；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cat file.txt <span class="p">|</span> <span class="k">while</span> <span class="nb">read</span> line<span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">	<span class="nb">echo</span> <span class="nv">$line</span>
</span></span><span class="line"><span class="cl"><span class="k">done</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="until-循环">until 循环</h3>
<p>until 是当条件不满足的时候进入循环，用法如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">count</span><span class="o">=</span><span class="m">0</span>
</span></span><span class="line"><span class="cl"><span class="k">until</span> <span class="o">[</span> <span class="nv">$count</span> -gt 10<span class="o">]</span><span class="p">;</span> don
</span></span><span class="line"><span class="cl">	<span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$count</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="o">((</span>count++<span class="o">))</span>
</span></span><span class="line"><span class="cl"><span class="k">done</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="基本函数定义和使用">基本函数定义和使用</h2>
<p><strong>函数定义</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">get_name<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">	<span class="nb">echo</span> <span class="s2">&#34;Aikenhong&#34;</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;you are </span><span class="k">$(</span>get_name<span class="k">)</span><span class="s2">&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>也可以使用 function 的关键字来替换</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="k">function</span> get_name<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">	<span class="nb">echo</span> <span class="s2">&#34;Aikenhong&#34;</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;you are </span><span class="k">$(</span>get_name<span class="k">)</span><span class="s2">&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>函数的参数传递</strong>：函数相当于另一个命名空间，所以其中的传入的函数参数列表和函数的参数列表本身是互不影响独立的。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 假设此时的脚本的参数输入$1=Aikenhong</span>
</span></span><span class="line"><span class="cl">print_string<span class="o">(){</span>
</span></span><span class="line"><span class="cl">	<span class="nb">echo</span> <span class="nv">$1</span>
</span></span><span class="line"><span class="cl">	<span class="nb">echo</span> <span class="nv">$2</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;author is </span><span class="nv">$1</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">print_string hello world
</span></span><span class="line"><span class="cl"><span class="c1"># 最终会输出author is Aikenhong hello world</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>传入参数的方式也如上面的例子所示。</p>
<p><strong>函数的返回值</strong>： <a href="https://www.runoob.com/linux/linux-shell-func.html" target="_blank" rel="noopener">https://www.runoob.com/linux/linux-shell-func.html</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">myfunc<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="nb">local</span> <span class="nv">myresult</span><span class="o">=</span><span class="s1">&#39;some value&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span> <span class="nv">$myresult</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl"><span class="nv">result</span><span class="o">=</span><span class="s2">&#34;</span><span class="k">$(</span>myfunc<span class="k">)</span><span class="s2">&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>函数用于抛出错误：</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">myfunc<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> myfunc<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;success&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span>
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;failure&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="reference">Reference</h2>
<ul>
<li><a href="https://github.com/jlevy/the-art-of-command-line/blob/master/README-zh.md" target="_blank" rel="noopener">The Art of Command Line</a>
</li>
<li><a href="https://wangchujiang.com/reference/docs/bash.html#bash-%e5%87%bd%e6%95%b0" target="_blank" rel="noopener">Quick Reference</a>
</li>
<li><a href="https://manpages.debian.org/unstable/manpages-zh/bash.1.zh_CN.html" target="_blank" rel="noopener">Man Page CN</a>
</li>
<li><a href="https://www.cnblogs.com/chengd/p/7803664.html" target="_blank" rel="noopener">Linux-shell 中 $(( ))、$ ( )与${ }</a>
</li>
</ul>
<h2 id="in-addition">In Addition</h2>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">g++ helloworld.cpp -o a
</span></span><span class="line"><span class="cl">./a &lt;input &gt;output</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="更新-mac-的-bash-版本">更新 Mac 的 bash 版本</h3>
<ol>
<li>安装新版 bash 版本 <code>brew install bash</code></li>
<li>查看安装完的 bash 路径 <code>which -a bash</code> 并通过 <code>bash --version</code> 确认新bash</li>
<li>注册新 bash：<code>sudo vim /etc/shells</code>，将新路径加在最后一样，重启终端即可。</li>
<li>Zsh 不需要操作，重启后会自动使用新的这个 bash。</li>
<li>但是注意执行的时候可能需要改成 bash 而不是 sh，sh 我们并没有更新。</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>Windows Configuration04 Dual-System-Ubuntu</title>
      <link>https://aikenh.cn/posts/dualsystemubuntu/</link>
      <pubDate>Sun, 22 Jan 2023 16:25:27 +0000</pubDate>
      <guid>https://aikenh.cn/posts/dualsystemubuntu/</guid>
      <description>&lt;p&gt;该文介绍基于 Windows11 系统的双系统安装和删除，安装的双系统选择 Ubuntu（开发还是比较推荐使用 WSL2 即可）&lt;/p&gt;
&lt;h2 id=&#34;install-dual-system&#34;&gt;Install Dual System&lt;/h2&gt;
&lt;p&gt;参考资料：&lt;a href=&#34;https://blog.csdn.net/NeoZng/article/details/122779035&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;全面解决各种问题&lt;/a&gt;
 &lt;a href=&#34;https://www.cnblogs.com/masbay/p/10745170.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;双系统安装&lt;/a&gt;
 &lt;a href=&#34;https://zhuanlan.zhihu.com/p/363640824&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Windows+Ubuntu20.04双系统安装教程&lt;/a&gt;
&lt;/p&gt;
&lt;h3 id=&#34;1-安装-u-盘制作&#34;&gt;1. 安装 u 盘制作&lt;/h3&gt;
&lt;p&gt;这里推荐 &lt;a href=&#34;https://github.com/ventoy/Ventoy&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;ventoy&lt;/a&gt;
 来做启动盘，ventoy 可以同时将很多系统的镜像放到一个 u 盘中，最最重要的是：干净简洁，可以参考其&lt;a href=&#34;https://www.ventoy.net/cn/doc_start.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;官方文档&lt;/a&gt;
来制作盘，制作后将镜像文件放到指定目录即可。&lt;/p&gt;
&lt;h3 id=&#34;2-硬盘分区&#34;&gt;2. 硬盘分区&lt;/h3&gt;
&lt;p&gt;win+s 搜索创建并格式化分区，找一块空闲空间较大的硬盘，右键压缩卷，设定好预留给 Linux 的空间即可（记住该大小，方便后续辨认，可以将各个盘的大小拍照记录下来，安装的时候别把 windows 覆盖了）。&lt;/p&gt;
&lt;p&gt;
&lt;div class=&#34;post-img-view&#34;&gt;
  &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230323085002.png&#34;&gt;
    &lt;img alt=&#34;image.png&#34; loading=&#34;lazy&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230323085002.png&#34;class=&#34;responsive-image&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230323085002.png&#34; style=&#34;display: block; margin: 0 auto;&#34;
      alt=&#34;image.png&#34;  /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;script&gt;
  document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
      var images = document.querySelectorAll(&#34;.responsive-image&#34;);
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + &#34;px&#34;;
      });
  });
&lt;/script&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;div class=&#34;post-img-view&#34;&gt;
  &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230323085239.png&#34;&gt;
    &lt;img alt=&#34;image.png&#34; loading=&#34;lazy&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230323085239.png&#34;class=&#34;responsive-image&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230323085239.png&#34; style=&#34;display: block; margin: 0 auto;&#34;
      alt=&#34;image.png&#34;  /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;script&gt;
  document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
      var images = document.querySelectorAll(&#34;.responsive-image&#34;);
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + &#34;px&#34;;
      });
  });
&lt;/script&gt;
&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>该文介绍基于 Windows11 系统的双系统安装和删除，安装的双系统选择 Ubuntu（开发还是比较推荐使用 WSL2 即可）</p>
<h2 id="install-dual-system">Install Dual System</h2>
<p>参考资料：<a href="https://blog.csdn.net/NeoZng/article/details/122779035" target="_blank" rel="noopener">全面解决各种问题</a>
 <a href="https://www.cnblogs.com/masbay/p/10745170.html" target="_blank" rel="noopener">双系统安装</a>
 <a href="https://zhuanlan.zhihu.com/p/363640824" target="_blank" rel="noopener">Windows+Ubuntu20.04双系统安装教程</a>
</p>
<h3 id="1-安装-u-盘制作">1. 安装 u 盘制作</h3>
<p>这里推荐 <a href="https://github.com/ventoy/Ventoy" target="_blank" rel="noopener">ventoy</a>
 来做启动盘，ventoy 可以同时将很多系统的镜像放到一个 u 盘中，最最重要的是：干净简洁，可以参考其<a href="https://www.ventoy.net/cn/doc_start.html" target="_blank" rel="noopener">官方文档</a>
来制作盘，制作后将镜像文件放到指定目录即可。</p>
<h3 id="2-硬盘分区">2. 硬盘分区</h3>
<p>win+s 搜索创建并格式化分区，找一块空闲空间较大的硬盘，右键压缩卷，设定好预留给 Linux 的空间即可（记住该大小，方便后续辨认，可以将各个盘的大小拍照记录下来，安装的时候别把 windows 覆盖了）。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230323085002.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230323085002.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230323085002.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230323085239.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230323085239.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230323085239.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>该预留的<strong>未分配</strong>空间，建议至少 30G 以上，如果需要开发和机器学习啥的话可以 50G、100G 以上。</p>
<h3 id="3-进入-bios-选择-u-盘启动">3. 进入 bios 选择 U 盘启动</h3>
<p>各个主板进入 bios 的方式不同，可以参考自己使用主板的进入方式，在开机的时候狂按某个 Fx 键，然后再启动方式中把启动盘调整到第一位，保存并重启。然后启动的时候就会进入 grub 界面。</p>
<p>（该部分主要参考 <a href="https://blog.csdn.net/NeoZng/article/details/122779035" target="_blank" rel="noopener">HNU 跃鹿战队</a>
 ）然后开始安装，安装前期一些比较常规的就不说了，关键的地方如下，记得选择其他选项，保证共存：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230323090755.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230323090755.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230323090755.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>找到未分配的空闲空间（可以按照预留的大小辅助判断），为其划分 Ubuntu 需要的几个分区：</p>
<ol>
<li>EFI 系统分区：逻辑分区 &gt;=512mb 用于加载和启动（不要太大浪费）（空间起始位置）</li>
<li>Ext4 日志文件系统：主分区、可以大一些，许多程序的默认安装地址在根目录的 <code>/opt</code> 中，挂载点：/</li>
<li>Ext4 日志文件系统：逻辑分区（看下默认的是啥）、剩下的都放在这，挂载点：/home</li>
</ol>
<p>然后安装的时候需要选择刚刚分的系统分区 EFI，千万注意不要和 windows 搞混了，可以通过设备和大小来划分，后续按照引导来即可。</p>
<h3 id="grub-开机引导界面美化">++Grub 开机引导界面美化</h3>
<p><a href="https://zhuanlan.zhihu.com/p/94331255" target="_blank" rel="noopener">https://zhuanlan.zhihu.com/p/94331255</a>
</p>
<h3 id="bitlocker-科普">BitLocker 科普</h3>
<p><a href="https://zhuanlan.zhihu.com/p/146450240" target="_blank" rel="noopener">【科普】Win10电脑的Bitlocker是什么</a>
</p>
<h2 id="remove-dual-system">Remove Dual System</h2>
<p>参考资料:  [华为云-删除双系统]（ <a href="https://bbs.huaweicloud.com/blogs/303695" target="_blank" rel="noopener">https://bbs.huaweicloud.com/blogs/303695</a>
 ）[知乎-删除双系统]（ <a href="https://zhuanlan.zhihu.com/p/392633489" target="_blank" rel="noopener">https://zhuanlan.zhihu.com/p/392633489</a>
 ）</p>
<p>Outline：1 （option）备份 - 2 修改默认启动项 - 3 删除硬盘分区 -4 删除开机启动引导 - 5 （option）重新分配磁盘空间</p>
<h3 id="1-backup">1. Backup</h3>
<p>有重要文件 / 对操作不完全清楚推荐备份，不在赘述。</p>
<h3 id="2-修改默认启动项">2. 修改默认启动项</h3>
<p>开机时，微星 F2 或 Del （不同品牌不同）进 Bios 修改 Boot 启动项，改回 windows 默认启动。</p>
<h3 id="3-删除-ubuntu-分区">3. 删除 Ubuntu 分区</h3>
<p>Windows + S 搜索硬盘分区打开磁盘管理器，删除 Ubuntu 相关分区，主要特征如下：</p>
<ul>
<li>为主分区</li>
<li>非 EFI 系统分区（!）、非恢复分区、非基本数据分区</li>
<li>不是 windows 当前使用的分区（删除的时候会提示非Windows）</li>
<li>没有命名</li>
<li>不是未分配的分区</li>
</ul>
<p>且一般会有磁盘 1-2 的区别，注意甄别。</p>
<p>删除完分区后，可以找到相邻的分区，使用拓展卷功能，将多余的空间分配过去即可。</p>
<p>折腾的话可以记住当前的系统大小分配备用。</p>
<h3 id="4-删除-ubuntu-开机引导">4. 删除 Ubuntu 开机引导</h3>
<p>A. 管理员身份打开 CMD/Powershell，进入磁盘管理</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">list</span> <span class="n">disk</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>B. 选择系统磁盘</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">select </span><span class="n">disk</span> <span class="mf">1</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>C. 查看对应的分区信息</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">list</span> <span class="n">partition</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>其中类型为系统的是 EFI 分区，Win11 一般为 100M，也可以再去磁盘管理器里面看一下。</p>
<p>D. 为其分配盘符, 注意盘符当前未被使用，可以 Win+E 打开资源管理器看看。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">select </span><span class="n">partition</span> <span class="mf">1</span>
</span></span><span class="line"><span class="cl"><span class="n">assign</span> <span class="n">letter</span><span class="p">=</span><span class="n">k</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>E. 盘无法直接进入，使用记事本访问，打开开始菜单，找到记事本，管理员权限打开。</p>
<p>右上角【文件】-&gt;【打开】进入新的磁盘，看到 EFI 文件夹，进入 EFI 文件夹，删除 Ubuntu 文件夹。</p>
<p>F. 返回刚刚的命令行界面，删除分配的盘符即可</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">remove</span> <span class="n">letter</span><span class="p">=</span><span class="n">k</span>
</span></span><span class="line"><span class="cl"><span class="n">exit</span> </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>结束</p>
]]></content:encoded>
    </item>
    <item>
      <title>Github Profile 个人主页</title>
      <link>https://aikenh.cn/posts/githubprofile/</link>
      <pubDate>Sat, 21 Jan 2023 21:25:24 +0000</pubDate>
      <guid>https://aikenh.cn/posts/githubprofile/</guid>
      <description>&lt;p&gt;&lt;strong&gt;Reference&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;本文介绍如何配置自己的 Github 的个人资料界面，同时会介绍相关美化个人资料的一些资源网站和项目，并简单介绍其用法。最终结果如下（还有许多优化的空间）：&lt;/p&gt;
&lt;p&gt;
&lt;div class=&#34;post-img-view&#34;&gt;
  &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230122113307.png&#34;&gt;
    &lt;img alt=&#34;image.png&#34; loading=&#34;lazy&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230122113307.png&#34;class=&#34;responsive-image&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230122113307.png&#34; style=&#34;display: block; margin: 0 auto;&#34;
      alt=&#34;image.png&#34;  /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;script&gt;
  document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
      var images = document.querySelectorAll(&#34;.responsive-image&#34;);
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + &#34;px&#34;;
      });
  });
&lt;/script&gt;
&lt;/p&gt;
&lt;h2 id=&#34;创建同名仓库&#34;&gt;创建同名仓库&lt;/h2&gt;
&lt;p&gt;Github 中创建用户名的同名仓库，该仓库的 README.md 将会在个人的资料页进行展示。(附上官方的说明如下)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;AikenH/AikenH is a special repository. Its &lt;code&gt;README.md&lt;/code&gt; will appear on your public profile.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;创建该仓库之后，我们对 Readme 的改动将会实时的同步到我们的个人界面，后续我们就只需要专注于编写和修改该 Readme 即可。&lt;/p&gt;
&lt;h2 id=&#34;相关资源推荐&#34;&gt;相关资源推荐&lt;/h2&gt;
&lt;p&gt;由于大家的审美和风格不同，这里不做设计上的推荐，仅推荐一些用于美化个人界面的资源和部分项目的用法（以本人的 blog 为例）。&lt;/p&gt;
&lt;p&gt;名字部分，简单文字转图片随便找一个&lt;a href=&#34;http://www.atoolbox.net/Tool.php?Id=723&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;工具箱&lt;/a&gt;
或者网站生成即可，不在赘述；&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这里是一个工具和推荐仓库的大全集&lt;/strong&gt;：&lt;a href=&#34;https://github.com/abhisheknaiidu/awesome-github-profile-readme#tools&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;abhisheknaiidu/awesome-github-profile-readme&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;这里是一些优秀的 &lt;a href=&#34;https://zzetao.github.io/awesome-github-profile/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;readme profile&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id=&#34;动态字幕&#34;&gt;动态字幕&lt;/h2&gt;
&lt;p&gt;介绍使用的动态字幕效果实现：&lt;a href=&#34;https://github.com/DenverCoder1/readme-typing-svg&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;DenverCoder1/readme-typing-svg&lt;/a&gt;
，进入其 &lt;a href=&#34;https://readme-typing-svg.demolab.com/demo/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Demo Site&lt;/a&gt;
，设定想要的样式和文字即可生成对应的 markdown 和 html 代码。&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><strong>Reference</strong></p>
<p>本文介绍如何配置自己的 Github 的个人资料界面，同时会介绍相关美化个人资料的一些资源网站和项目，并简单介绍其用法。最终结果如下（还有许多优化的空间）：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230122113307.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230122113307.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230122113307.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="创建同名仓库">创建同名仓库</h2>
<p>Github 中创建用户名的同名仓库，该仓库的 README.md 将会在个人的资料页进行展示。(附上官方的说明如下)</p>
<blockquote>
<p>AikenH/AikenH is a special repository. Its <code>README.md</code> will appear on your public profile.</p>
</blockquote>
<p>创建该仓库之后，我们对 Readme 的改动将会实时的同步到我们的个人界面，后续我们就只需要专注于编写和修改该 Readme 即可。</p>
<h2 id="相关资源推荐">相关资源推荐</h2>
<p>由于大家的审美和风格不同，这里不做设计上的推荐，仅推荐一些用于美化个人界面的资源和部分项目的用法（以本人的 blog 为例）。</p>
<p>名字部分，简单文字转图片随便找一个<a href="http://www.atoolbox.net/Tool.php?Id=723" target="_blank" rel="noopener">工具箱</a>
或者网站生成即可，不在赘述；</p>
<p><strong>这里是一个工具和推荐仓库的大全集</strong>：<a href="https://github.com/abhisheknaiidu/awesome-github-profile-readme#tools" target="_blank" rel="noopener">abhisheknaiidu/awesome-github-profile-readme</a>
</p>
<p>这里是一些优秀的 <a href="https://zzetao.github.io/awesome-github-profile/" target="_blank" rel="noopener">readme profile</a>
</p>
<h2 id="动态字幕">动态字幕</h2>
<p>介绍使用的动态字幕效果实现：<a href="https://github.com/DenverCoder1/readme-typing-svg" target="_blank" rel="noopener">DenverCoder1/readme-typing-svg</a>
，进入其 <a href="https://readme-typing-svg.demolab.com/demo/" target="_blank" rel="noopener">Demo Site</a>
，设定想要的样式和文字即可生成对应的 markdown 和 html 代码。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">p</span> <span class="na">align</span><span class="o">=</span><span class="s">&#34;center&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://git.io/typing-svg&#34;</span><span class="p">&gt;&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://readme-typing-svg.demolab.com?font=Fira+Code&amp;pause=1000&amp;color=CC7DF7&amp;width=435&amp;lines=The+five+boxing+wizards+jump+quickly&#34;</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;Typing SVG&#34;</span> <span class="p">/&gt;&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>并通过 Html 样式指定居中对齐，将其放入 readme 中即可，效果如下：</p>
<p align="center">
	<a href=" https://git.io/typing-svg"><img src=" https://readme-typing-svg.demolab.com?font=Fira+Code&pause=1000&color=CC7DF7&width=435&lines=The+five+boxing+wizards+jump+quickly" alt="Typing SVG" /></a>
</p>
<h2 id="统计卡片">统计卡片</h2>
<p>笔者更喜欢统计卡片 <a href="https://github.com/anuraghazra/github-readme-stats/blob/master/docs/readme_cn.md" target="_blank" rel="noopener">anuraghazra/github-readme-stats</a>
 的风格和 ui，也可以展示特定的仓库等，统计指标更为完善。</p>
<p>使用时只需要指定 Username 即可，并根据自己的需求，添加和调整对应的参数，如添加 <code>&amp;count_private=true</code>。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://github-readme-stats.vercel.app/api?username=anuraghazra&amp;count_private=true&amp;show_icons=true&amp;theme=synthwave">
    <img alt="Anurag&rsquo;s GitHub stats" loading="lazy" src="https://github-readme-stats.vercel.app/api?username=anuraghazra&count_private=true&show_icons=true&theme=synthwave"class="responsive-image" src="https://github-readme-stats.vercel.app/api?username=anuraghazra&amp;count_private=true&amp;show_icons=true&amp;theme=synthwave" style="display: block; margin: 0 auto;"
      alt="Anurag&rsquo;s GitHub stats"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>该项目也能展示如：热门语言卡片、pin 其他的 repo 等等功能的卡片。</p>
<h2 id="徽章定制">徽章定制</h2>
<p>徽章定制主要是 <a href="https://shields.io" target="_blank" rel="noopener">Shields</a>
，输入自己的信息和颜色定制特定徽章，结合 Html 使用 href 超链接为佳，同时可以使用下面其他的样式来改变自己的徽标。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>url</span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code class="language-url" data-lang="url">https://img.shields.io/badge/&lt;LABEL&gt;-&lt;MESSAGE&gt;-&lt;COLOR&gt;</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>原始默认的样式如下：

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://img.shields.io/badge/github-aikenh-blue">
    <img loading="lazy" src="https://img.shields.io/badge/github-aikenh-blue"class="responsive-image" src="https://img.shields.io/badge/github-aikenh-blue" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>可以改变写法，引入样式进行改变：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>url</span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code class="language-url" data-lang="url">https://img.shields.io/static/v1?label=github&amp;message=aikenh&amp;color=blue&amp;style=for-the-badge&amp;logo=appveyor</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>变成如下的形式等等，其他的参考网站。

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://img.shields.io/static/v1?label=github&amp;message=aikenh&amp;color=blue&amp;style=for-the-badge&amp;logo=appveyor">
    <img loading="lazy" src="https://img.shields.io/static/v1?label=github&message=aikenh&color=blue&style=for-the-badge&logo=appveyor"class="responsive-image" src="https://img.shields.io/static/v1?label=github&amp;message=aikenh&amp;color=blue&amp;style=for-the-badge&amp;logo=appveyor" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>使用 <a href="https://github.com/DenverCoder1/custom-icon-badges/blob/main/README.md" target="_blank" rel="noopener">DenverCoder1/custom-icon-badges</a>
 基于获取的 shields 的徽标进行进一步的自定义，得到更多样式，可以自己上传标志，或者打上更多标签。</p>
<ul>
<li>修改 shields 的 url</li>
<li>选择其中的各种 slug 和 log 去进一步自定义该徽标</li>
</ul>
<p>例如下面这个徽标，可以基于其 example usage 修改其中的文本和 icon 部分即可得到类似的效果。同样结合 html 的样式和 href 使用更佳。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span></span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code>&lt;a href=&#34;https://aikenh.cn&#34;&gt;&lt;img alt=&#34;github&#34; title=&#34;AikenD&#34; src=&#34;https://custom-icon-badges.demolab.com/badge/-aiken%20blog-palegreen?style=for-the-badge&amp;logo=package&amp;logoColor=black&#34;&gt;&lt;/a&gt;</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><a href=" https://aikenh.cn"><img alt="github" title="AikenD" src=" https://custom-icon-badges.demolab.com/badge/-aiken%20blog-palegreen?style=for-the-badge&logo=package&logoColor=black"></a></p>
<h2 id="统计奖杯">统计奖杯</h2>
<p>统计奖杯 <a href="https://github.com/ryo-ma/github-profile-trophy" target="_blank" rel="noopener">ryo-ma/github-profile-trophy</a>
 可以根据 Github 账号的 Commit 等信息来统计 Github 的活跃程度，并通过奖杯的方式呈现出来（账户较为活跃的就可以使用这个来展示）。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span></span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code>[![trophy](https://github-profile-trophy.vercel.app/?username=AikenH)](https://github.com/ryo-ma/github-profile-trophy)</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><a href="https://github.com/ryo-ma/github-profile-trophy" target="_blank" rel="noopener">
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://github-profile-trophy.vercel.app/?username=AikenH">
    <img alt="trophy" loading="lazy" src="https://github-profile-trophy.vercel.app/?username=AikenH"class="responsive-image" src="https://github-profile-trophy.vercel.app/?username=AikenH" style="display: block; margin: 0 auto;"
      alt="trophy"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</a>
</p>
<p>使用方法较为简单，只要修改提供链接的 username 改为自己的即可，当然也有一些包括设定 rank 或者显示特定奖杯之类的，可以在 readme 界面看看介绍，并进行自定义即可。</p>
<h2 id="其他">其他</h2>
<ol>
<li>简单的 readme 生成工具：<a href="https://rahuldkjain.github.io/gh-profile-readme-generator/" target="_blank" rel="noopener">rahuldkjain/github-profile-readme-generator</a>
 可以借助这个生成工具得到部分产品图标。</li>
<li>Icons of bands，产品图标 svg 大全：<a href="https://simpleicons.org" target="_blank" rel="noopener">simple icons</a>
，获取不同的产品图标，可以在定制 widget 什么的时候使用。</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>Nodejs、yarn、npm关系辨析</title>
      <link>https://aikenh.cn/posts/nodes/</link>
      <pubDate>Sun, 09 Oct 2022 13:33:00 +0000</pubDate>
      <guid>https://aikenh.cn/posts/nodes/</guid>
      <description>&lt;p&gt;@AikenH 2022 Node-JS-Chapter1&lt;/p&gt;
&lt;p&gt;参考：&lt;a href=&#34;https://blog.csdn.net/Newbie___/article/details/104759861&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;包管理工具npm、yarn以及nvm简介及简单使用&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id=&#34;concept-概念&#34;&gt;Concept 概念&lt;/h2&gt;
&lt;p&gt;对 Node，NPM，JS，Yarn，NVM 的概念和作用进行一个辨析和介绍，了解各自的含义和职责，进而理解我们使用的到底是什么，环境怎么管理，怎么自定义和进行改动等。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;JS&lt;/strong&gt;在 1995 年诞生，Nodejs 在 2009 年诞生，在此之前 JS 只能在浏览器中使用（google 开发的 chrome 的 V8 引擎），NodeJS（第三方作者想直接在计算机运行 JS，让其脱离浏览器）相当于提供的一个 JS 的运行环境，用来支持 JS 的执行，也就是 JS 的一个 runtime system。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;由此，JS 除了 web 前端编程，又可以支持后台开发、GUI 开发、APP 开发和 CLI 工具开发&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Nodejs&lt;/strong&gt;和 JS 的概念已经在上述清楚了，这里说一下 nodejs 组成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;V8 引擎将 JS 编译成机器码，提高运行速度；&lt;/li&gt;
&lt;li&gt;本地模块：使用 C/C++实现的一些高性能开源库；&lt;/li&gt;
&lt;li&gt;标准库：封装 C/C++的一些本地模块的接口，转换为 JS 接口，就是 Nodejs 的标准库，其良好的设计也赋予 Nodejs 强大的生命力；&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.npmjs.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;NPM&lt;/a&gt;
 是随 NodeJS 一起安装的包管理工具（提供下载，版本校验，兼容性校验等功能），就像 pip、conda 帮助 Nodejs 管理并解决本地部署的问题。&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;Yarn&lt;/strong&gt;：由 Facebook、Google、Exponent 和 Tilde 联合推出的 JS 包管理工具，和 NPM 就像是 pip 和 conda 的关系，其仍然使用 NPM 的 registry，不过提供了全新的 CLI 来进行管理（也就是管理包的代码和逻辑有区别）&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>@AikenH 2022 Node-JS-Chapter1</p>
<p>参考：<a href="https://blog.csdn.net/Newbie___/article/details/104759861" target="_blank" rel="noopener">包管理工具npm、yarn以及nvm简介及简单使用</a>
</p>
<h2 id="concept-概念">Concept 概念</h2>
<p>对 Node，NPM，JS，Yarn，NVM 的概念和作用进行一个辨析和介绍，了解各自的含义和职责，进而理解我们使用的到底是什么，环境怎么管理，怎么自定义和进行改动等。</p>
<ul>
<li>
<p><strong>JS</strong>在 1995 年诞生，Nodejs 在 2009 年诞生，在此之前 JS 只能在浏览器中使用（google 开发的 chrome 的 V8 引擎），NodeJS（第三方作者想直接在计算机运行 JS，让其脱离浏览器）相当于提供的一个 JS 的运行环境，用来支持 JS 的执行，也就是 JS 的一个 runtime system。</p>
<blockquote>
<p>由此，JS 除了 web 前端编程，又可以支持后台开发、GUI 开发、APP 开发和 CLI 工具开发</p>
</blockquote>
</li>
<li>
<p><strong>Nodejs</strong>和 JS 的概念已经在上述清楚了，这里说一下 nodejs 组成：</p>
<ul>
<li>V8 引擎将 JS 编译成机器码，提高运行速度；</li>
<li>本地模块：使用 C/C++实现的一些高性能开源库；</li>
<li>标准库：封装 C/C++的一些本地模块的接口，转换为 JS 接口，就是 Nodejs 的标准库，其良好的设计也赋予 Nodejs 强大的生命力；</li>
</ul>
</li>
<li>
<p><a href="https://www.npmjs.com/" target="_blank" rel="noopener">NPM</a>
 是随 NodeJS 一起安装的包管理工具（提供下载，版本校验，兼容性校验等功能），就像 pip、conda 帮助 Nodejs 管理并解决本地部署的问题。</p>
<ul>
<li>允许下载别人写好的第三方包到本地使用；</li>
<li>允许下载安装别人编写的命令行程序；</li>
<li>允许上传包或命令行程序给别人使用；</li>
</ul>
</li>
<li>
<p><strong>Yarn</strong>：由 Facebook、Google、Exponent 和 Tilde 联合推出的 JS 包管理工具，和 NPM 就像是 pip 和 conda 的关系，其仍然使用 NPM 的 registry，不过提供了全新的 CLI 来进行管理（也就是管理包的代码和逻辑有区别）</p>
</li>
<li>
<p><strong>NVM</strong>：Conda 的另一个功能，在同个电脑上管理多个 Node 版本；</p>
</li>
<li>
<p><strong>CLI</strong>（Command-line-interface），相当于没有 UI 界面的命令行程序；</p>
</li>
<li>
<p><strong>Cnpm</strong>：为了解决国内链接 Npm registry 的困难，淘宝自己的 npm 镜像（不过现在没啥用了好像）；</p>
</li>
</ul>
<h3 id="runtime">Runtime</h3>
<p><strong>什么是runtime</strong>：<a href="https://www.zhihu.com/question/20607178" target="_blank" rel="noopener">运行时（runtime）是什么意思</a>
、<a href="https://en.wikipedia.org/wiki/Runtime_system" target="_blank" rel="noopener">Runtime system - Wikipedia</a>
、<a href="http://c.biancheng.net/view/9338.html" target="_blank" rel="noopener">Node.js是什么？运行时是什么</a>
</p>
<p><strong>runtime</strong>主要有几种类型：</p>
<ol>
<li>
<p>「程序运行的时候」，即程序生命周期的一个阶段。也就是运行阶段。</p>
</li>
<li>
<p>「运行时库」，支撑应用级语言（c，c++，Rust）的一些正常功能的 lib，对部分“标准指令”进行包装，（标准库）优雅的映射到汇编。<strong>也就是程序运行的时候</strong>所需要依赖的库。

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/image-20221018135959777.png">
    <img alt="image-20221018135959777" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/image-20221018135959777.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/image-20221018135959777.png" style="display: block; margin: 0 auto;"
      alt="image-20221018135959777"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
</li>
<li>
<p>「运行时系统」某门语言的宿主环境：Node.js 是一个 JavaScript 的运行时。运行时系统主要是一些高级语言的概念，可以理解成一个更大、更全的运行时库，低级语言由于强指定类型等原因，可直接直译成机器码，而依赖于编译的语言，就需要一个运行时系统来实现语言的运行。</p>
<blockquote>
<p>JAVA运行时是JRE（Java Runtime Environment），C #运行时是CLR ，他们都需要在 OS 上单独安装，借由他们来执行相应语言的程序（编译出的字节码），而对于 JS 来说，JS 引擎不带 IO 支持的虚拟机，因此需要浏览器和 Node 这样的「JS 运行时」才能让他控制文件、网络、图形等。</p>
</blockquote>
<p>典型的高级语言的「运行时系统」需要如下的组件：</p>
<ul>
<li>
<p>一个解释执行字节码的虚拟机，多半得带个垃圾回收器。</p>
</li>
<li>
<p>如果语言是源码解释执行，那么需要一个编译器前端做词法分析和语法分析。</p>
</li>
<li>
<p>如果运行时支持 JIT 优化，那么还得藏着个编译器后端（动态生成[机器码]( <a href="https://www.zhihu.com/search?q=" target="_blank" rel="noopener">https://www.zhihu.com/search?q=</a>
机器码&amp;search_source=Entity&amp;hybrid_search_source=Entity&amp;hybrid_search_extra= {&ldquo;sourceType&rdquo;%3A&quot;answer&quot;%2C&quot;sourceId&quot;%3A2133648600})）。</p>
</li>
<li>
<p>IO 相关能力，比如 Node.js 的 <code>fs.readFile</code> 之类。</p>
</li>
</ul>
<p>已经相当于一个复杂的基础软件系统了。</p>
<p>**总结：**运行时就是，类似一些编好的 dll、标准库、解释器等，支持 JS 运行的组件和工具的合集，被统称为运行时。</p>
</li>
</ol>
<h2 id="nodejs--npm">Nodejs &amp; NPM</h2>
<h3 id="安装和配置">安装和配置</h3>
<p>安装：windows 直接去 <a href="https://nodejs.org/en/download" target="_blank" rel="noopener">nodejs</a>
 -&gt; <a href="https://github.com/nodesource/distributions" target="_blank" rel="noopener">nodesource/distributions: NodeSource</a>
 官网下载安装。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># debian(ubuntu)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 首先更新NOdejs的软件源，基于上述提供的网站中获取指定连接和更新方式。</span>
</span></span><span class="line"><span class="cl">curl -sL https://deb.nodesource.com/setup_14.x <span class="p">|</span> sudo -E bash -
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 接着使用apt命令下载nodejs 和 npm</span>
</span></span><span class="line"><span class="cl">sudo apt-get install npm, nodejs
</span></span><span class="line"><span class="cl"><span class="c1"># 可能还需要安装一些c++依赖</span>
</span></span><span class="line"><span class="cl">sudo apt install build-essential -y
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># macos </span>
</span></span><span class="line"><span class="cl">brew install node
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 查看版本</span>
</span></span><span class="line"><span class="cl">npm -v 
</span></span><span class="line"><span class="cl">node -V</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>更新 npm 版本</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo npm install npm -g</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>NPM 设置代理 registry 地址，使用国内镜像</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm config <span class="nb">set</span> registry https://registry.npm.taobao.org
</span></span><span class="line"><span class="cl"><span class="c1"># 使用下面的命令进行检查</span>
</span></span><span class="line"><span class="cl">npm config get registry</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="常用操作">常用操作</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm install &lt;package&gt; <span class="c1"># 本地安装</span>
</span></span><span class="line"><span class="cl">npm install &lt;package&gt; -g <span class="c1"># 全局安装 </span>
</span></span><span class="line"><span class="cl"><span class="c1"># npm i 为 install的简写</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 卸载模块</span>
</span></span><span class="line"><span class="cl">npm uninstall &lt;package&gt;
</span></span><span class="line"><span class="cl">npm ls <span class="c1"># 查看是否卸载成功,或者去/node_modules目录check</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 搜索模块</span>
</span></span><span class="line"><span class="cl">npm search &lt;package&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 更新模块</span>
</span></span><span class="line"><span class="cl">npm update &lt;package&gt;</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>node 重新安装依赖包</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">rm -rv node_modules <span class="c1"># del those files we downlaods</span>
</span></span><span class="line"><span class="cl">rm package-lock.json <span class="c1"># del the install info </span>
</span></span><span class="line"><span class="cl">npm cache clear --force
</span></span><span class="line"><span class="cl">npm install</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>npm 设置代理</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">npm config <span class="nb">set</span> <span class="nv">proxy</span><span class="o">=</span>http://127.0.0.1:8890
</span></span><span class="line"><span class="cl"><span class="c1"># 取消</span>
</span></span><span class="line"><span class="cl">npm config delete proxy
</span></span><span class="line"><span class="cl"><span class="c1"># 查看</span>
</span></span><span class="line"><span class="cl">npm config list</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="packagejson">Package.json</h3>
<p>npm将每个使用npm的工程都看成一个包，包的信息是通过 <code>package.json</code> 配置文件来描述的，可以手动创建，但是大多数时候是使用 <code>npm init</code> 创建（可以创建一个看看默认值）</p>
<p><strong>package-lock.json</strong> 锁定具体版本</p>
<p>npm 在安装包的时候，会记录安装包时候准确的依赖项（包含版本信息），若我们保留了该文件，在安装的时候会根据上面的准确版本进行安装，最大程度的避免了差异。</p>
<p>package.json 文件最重要的作用，是记录当前工程的依赖</p>
<ul>
<li>dependencies：生产环境的依赖包</li>
<li>devDependencies：仅开发环境的依赖包</li>
</ul>
<p>配置好依赖后，使用下面的命令即可安装依赖</p>
<ul>
<li>本地安装所有依赖 安装所有依赖 dependencies + devDependencies</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm i</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>Install</strong>的时候添加参数，可将包添加到依赖项的 package.json 中</p>
<ul>
<li>安装依赖到生产环境</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm i &lt;package&gt;
</span></span><span class="line"><span class="cl">npm i --save &lt;package&gt;
</span></span><span class="line"><span class="cl">npm i -S &lt;package&gt;</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>安装依赖到开发环境</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm i --save-dev &lt;package&gt;
</span></span><span class="line"><span class="cl">npm i -D &lt;package&gt;</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="npm-中包的安装路径">NPM 中包的安装路径</h3>
<p>节选自参考链接 <a href="https://cloud.tencent.com/developer/article/1834667" target="_blank" rel="noopener">Link</a>
</p>
<ol>
<li>本地安装 <code>npm install</code> 安装到当前路径的 node_modules 中</li>
<li>全局安装添加 <code>-g</code> 参数</li>
</ol>
<p>全局文件的安装地址在: <code>npm root -g </code>  | <code>npm config get prefix</code></p>
<h2 id="yarn">YARN</h2>
<p><a href="https://yarnpkg.com/cli/install" target="_blank" rel="noopener">YARN</a>
 相比 NPM 有以下的优点，但是 npm6 之后，npm 和 yarn 非常接近，所以后续很多从 yarn 转回 npm 的</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">- 使用扁平的目录结构
</span></span><span class="line"><span class="cl">- 并行下载
</span></span><span class="line"><span class="cl">- 使用本地缓存
</span></span><span class="line"><span class="cl">- 控制台仅输出关键信息
</span></span><span class="line"><span class="cl">- yarn-lock记录确切依赖
</span></span><span class="line"><span class="cl">- 增加了某些功能强大的命令
</span></span><span class="line"><span class="cl">- 让既有的命令更加语义化
</span></span><span class="line"><span class="cl">- 安装的CLI工具可以使用yarn直接启动
</span></span><span class="line"><span class="cl">- 将全局安装的目录当成普通的工程，生成package.json文件，便于全局安装移植</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="安装-yarn">安装 yarn</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm install -g yarn</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">yarn --version</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="package-管理">package 管理</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">yarn install &lt;package&gt;
</span></span><span class="line"><span class="cl">yarn remove &lt;package&gt;</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="nvm">NVM</h2>
<p><a href="https://github.com/nvm-sh/nvm" target="_blank" rel="noopener">NVM</a>
 用来管理 node 版本，便于适应多个 node 环境，在之间进行切换。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">nvm -v <span class="c1"># 查看版本</span>
</span></span><span class="line"><span class="cl">nvm list <span class="c1"># 查看node版本号</span>
</span></span><span class="line"><span class="cl">nvm use &lt;version&gt; <span class="c1"># 使用指定版本号的node</span>
</span></span><span class="line"><span class="cl">nvm install &lt;version&gt; <span class="c1"># 下载指定版本的node</span>
</span></span><span class="line"><span class="cl">nvm uninstall &lt;version&gt; <span class="c1"># 卸载指定版本的node</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>设置淘宝镜像</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">nvm node_mirror https://npm.taobao.org/mirrors/node/
</span></span><span class="line"><span class="cl">nvm npm_mirror https://npm.taobao.org/mirrors/npm/</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script>]]></content:encoded>
    </item>
    <item>
      <title>一次基于Vue和Django的前后端开发实践</title>
      <link>https://aikenh.cn/posts/custom_web/</link>
      <pubDate>Sun, 02 Oct 2022 18:00:00 +0000</pubDate>
      <guid>https://aikenh.cn/posts/custom_web/</guid>
      <description>build your website by django and vue, save info in mysql</description>
      <content:encoded><![CDATA[<head>
    
    <script src="https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/crypto-js/3.1.9-1/crypto-js.js"></script>
</head>





<div class="hugo-encryptor-container">
  <div class="hugo-encryptor-prompt">
    
      <p>文章的部分内容被密码保护：</p>
    
  </div>
  <div class="hugo-encryptor-form">
    <input
      class="hugo-encryptor-input"
      placeholder='请输入密码'
    />
    <input
      class="hugo-encryptor-button"
      type="button"
      value='CLICK'
      onclick="_click_handler(this)"
    />
  </div>
  <div
    class="hugo-encryptor-cipher-text"
    data-password="aikenhong_blog"
    style="display: none;"
  >
    <span style="display: none;">--- DON'T MODIFY THIS LINE ---</span>
    <p>@Aikenhong 2022 介绍基于Tdesign和Django的界面安装和前后端联调，ubuntu version，</p>
<p>该文章首先介绍如何配置环境，后续基于现有项目来介绍如何从零来构建基本的网页和后端服务。</p>
<h2 id="基本信息">基本信息</h2>
<p>（已完成）下载编写好的网页压缩包：web-design，里面包含了vue和django模块。</p>
<p>路径两种方式打开：</p>
<ol>
<li>（命令行） <code>cd ~/workspace/web_design_group10/</code></li>
<li>（资源管理器）主目录下的workspace/web_design_group10</li>
</ol>
<p>编辑代码方式：</p>
<ol>
<li>使用vscode打开该文件夹进行编辑</li>
</ol>
<h3 id="启动服务">启动服务</h3>
<p>（以下的操作都分别基于web_design_group10路径）完整的网页启动需要分别启动前后端的服务，并均保持开启状态，所以需要使用两个终端窗口来分别启动。</p>
<ol>
<li>前端服务：在view-design路径下使用命令:<code>npm run dev</code>，可参考VUE启动</li>
<li>后端服务：在vuebackend页面使用命令：</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">python manager.py runserver</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>（python版本需要是3以上）</p>
<ol start="3">
<li>数据库服务：数据库安装后好像是默认启动的，如果发现有数据库的错误，按照ubuntu 启动mysql执行。</li>
</ol>
<p>在启动服务之前，有一些环境需要配置，接下来我们将描述初始的环境准备。</p>
<h2 id="环境配置ubuntu">环境配置（Ubuntu）</h2>
<p>配置主要有几个部分组成：配置前端环境（vue、node）、配置数据库（mysql）、配置后端（python包），我们首先描述前端环境的配置。</p>
<p>**特定项目迁移：**只需要安装node和NPM，然后再对应目录npm i即可</p>
<p>**初始化一个项目：**安装完node、npm之后，安装vue和tdesign，参考对应的官方文档即可，（npm install）</p>
<h3 id="前端环境配置">前端环境配置</h3>
<p>前端项目基于NodeJS，所以我们需要首先安装Node和NPM，在Ubuntu中安装Node的命令如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 首先更新NOdejs的软件源，基于基于需要的版本修改其中的版本号 14/16</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 接着使用apt命令下载nodejs 和 npm</span>
</span></span><span class="line"><span class="cl">sudo apt-get install npm, nodejs
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 查看版本验证安装是否成功</span>
</span></span><span class="line"><span class="cl">node -V
</span></span><span class="line"><span class="cl">npm -V</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>接着对特定前端（NodeJS）项目安装依赖</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">cd</span> /web-design-group10/view-design
</span></span><span class="line"><span class="cl"><span class="c1"># 执行如下命令可直接根据项目的进行package的安装</span>
</span></span><span class="line"><span class="cl"><span class="c1"># npm install 可以简写为 npm i</span>
</span></span><span class="line"><span class="cl">npm install</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>安装完基本依赖后，即可启动前端服务看看页面是否正常运行，默认的访问路径是localhost:3001</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 启动前端项目在view-design目录下</span>
</span></span><span class="line"><span class="cl">npm run dev 
</span></span><span class="line"><span class="cl"><span class="c1"># 启动后可以看到对应的端口和ip（建议首先使用localhost对前后端进行调试）</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>启动服务后可以边修改页面边预览效果（感觉不对劲就手动重启下，有时候响应会出现问题）</p>
<h3 id="mysql环境配置">MySQL环境配置</h3>
<p>由于Django（后面我们会讲）将诸多对于数据库，例如MySQL的操作都集成成了Python语句，所以对于MySQL配置的部分，我们只需要做如下的准备：</p>
<p><strong>安装MySQL</strong> -&gt; <strong>初始化MySQL（设置密码）</strong>-&gt;<strong>为后端创建一个初始的数据库</strong> -&gt; <strong>在DJango</strong>中做好对应的设置。</p>
<p>在Ubuntu上安装mysql：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># install mysql(in ubuntu)</span>
</span></span><span class="line"><span class="cl">sudo apt-get install mysql-client
</span></span><span class="line"><span class="cl">sudo apt-get install mysql-server</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>初始化MySQL（设置密码）：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 进入mysql</span>
</span></span><span class="line"><span class="cl">sudo mysql</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>进入mysql之后，通过设置基本的密码来初始化sql的服务（执行别的命令之前我们需要该密码）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="n">mysql</span><span class="o">&gt;</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">alter</span><span class="w"> </span><span class="k">user</span><span class="w"> </span><span class="s1">&#39;root&#39;</span><span class="o">@</span><span class="s1">&#39;localhost&#39;</span><span class="w"> </span><span class="n">indentify</span><span class="w"> </span><span class="k">with</span><span class="w"> </span><span class="n">mysql_native_password</span><span class="w"> </span><span class="k">by</span><span class="w"> </span><span class="s1">&#39;passwd@of@my&#39;</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="o">#</span><span class="w"> </span><span class="err">退出</span><span class="n">mysql数据库</span><span class="err">，验证是否正确初始化</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">mysql</span><span class="o">&gt;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="n">exit</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>​	上述命令中，密码的小引号不能省略</p>
<p>接着验证密码：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mysql -u root -p
</span></span><span class="line"><span class="cl"><span class="c1"># 输入密码，如果正确的话会进入数据库，到这里已经可以了，我们开始创建后续django使用的数据库</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 通过show databases; 可以查看现在创建好的所有数据库</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>创建项目所需的数据库（建议和项目文件夹同名，方便记忆）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>mysql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="c1"># 创建数据库并设定utf8编码，避免编码问题
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">mysql</span><span class="o">&gt;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">create</span><span class="w"> </span><span class="k">database</span><span class="w"> </span><span class="o">&lt;</span><span class="n">project</span><span class="o">-</span><span class="n">name</span><span class="o">&gt;</span><span class="w"> </span><span class="k">character</span><span class="w"> </span><span class="kt">set</span><span class="w"> </span><span class="n">utf8</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1"># 使用show databass查看是否正确创建
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">mysql</span><span class="o">&gt;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">show</span><span class="w"> </span><span class="k">databases</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1"># 使用use &lt;database-name&gt; 进入对应的数据库
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">mysql</span><span class="o">&gt;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">use</span><span class="w"> </span><span class="o">&lt;</span><span class="k">databases</span><span class="o">-</span><span class="n">name</span><span class="o">&gt;</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1"># 使用show tables查看已经创建好的表格
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">mysql</span><span class="o">&gt;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">show</span><span class="w"> </span><span class="kp">tables</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>到这里对于数据库的配置就告一段落，后续只需要在Django中设置如下的内容即可：</p>
<ul>
<li>使用的数据库架构（mysql or else）</li>
<li>使用的具体数据库，（我们为后端创建的那个）</li>
<li>数据库的访问密码</li>
</ul>
<p>之后就可以在Django的python代码中执行常见的数据库操作来进行响应的增删改查。</p>
<p><strong>参考链接</strong>：<a href="https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-ubuntu-20-04" target="_blank" rel="noopener">install</a>
、<a href="https://www.liujiangblog.com/course/django/165" target="_blank" rel="noopener">刘江</a>
</p>
<h3 id="django环境配置with-mysql">Django环境配置（with mysql）</h3>
<p><a href="https://docs.djangoproject.com/zh-hans/4.1/" target="_blank" rel="noopener">Django</a>
作为Python的一个库（Lib）安装过程实际上是配置一个python环境，这里主要考虑到结合mysql需要安装一些额外的库和设置，同样，会分成以下的几步：</p>
<p><strong>安装Django</strong>-&gt;<strong>安装Django-Mysql需要的库</strong>-&gt;<strong>建立Django和mysql连接</strong>（填写上面提到的密码等）-&gt;<strong>初始化项目</strong></p>
<ol>
<li><strong>安装Django</strong></li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 如果没有pip的话试试pip3，如果是pip3安装的，最后启动服务的时候要记得用python3来启动</span>
</span></span><span class="line"><span class="cl">pip install django</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="2">
<li><strong>安装mysqlclient</strong></li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">pip install mysqlclient</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="3">
<li><strong>创建一个空的Django项目</strong>：</li>
</ol>
<p>（cd）移动到一个我们放置项目的空目录（忽略&lt;&gt;），就会创建一个my-project-name的项目：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">django-admin startproject &lt;my-project-name&gt;</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>其文件结构如下（具体作用解析：https://docs.djangoproject.com/zh-hans/4.1/intro/tutorial01/）：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mysite/
</span></span><span class="line"><span class="cl">    manage.py
</span></span><span class="line"><span class="cl">    mysite/
</span></span><span class="line"><span class="cl">        __init__.py
</span></span><span class="line"><span class="cl">        settings.py
</span></span><span class="line"><span class="cl">        urls.py         <span class="c1"># 接口的路由管理,也就是我们的接口在哪边访问</span>
</span></span><span class="line"><span class="cl">        asgi.py
</span></span><span class="line"><span class="cl">        wsgi.py</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>创建一个具体的“APP”，又被称作<strong>应用</strong>，这里的<strong>应用</strong>和上面创建的<strong>项目</strong>的区别在于（摘自官网）：</p>
<blockquote>
<p>项目和应用有什么区别？应用是一个专门做某件事的网络应用程序——比如博客系统，或者公共记录的数据库，或者小型的投票程序。项目则是一个网站使用的配置和应用的集合。项目可以包含很多个应用。应用可以被很多个项目使用。</p>
</blockquote>
<p>个人讲项目理解为项目，主要提供Django的基本功能和设置环境；应用则是我们进行具体功能开发的主要地方，比如我们这里创建一个webapi的应用，用来编写特定网站需要的所有接口：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 初始化APP</span>
</span></span><span class="line"><span class="cl">python manager.py startapp webapi</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>Django会创建路径如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">webapi/
</span></span><span class="line"><span class="cl">    __init__.py 
</span></span><span class="line"><span class="cl">    admin.py            <span class="c1"># 包含django管理界面的设置</span>
</span></span><span class="line"><span class="cl">    apps.py             <span class="c1"># 包含webapi配置的设置</span>
</span></span><span class="line"><span class="cl">    migrations/
</span></span><span class="line"><span class="cl">        __init__.py
</span></span><span class="line"><span class="cl">    models.py            <span class="c1"># 定义数据库中的表</span>
</span></span><span class="line"><span class="cl">    tests.py
</span></span><span class="line"><span class="cl">    views.py             <span class="c1"># 定义API</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>创建完APP（应用后），我们需要在项目的设置中安装</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">vim vuebackend/vuebackend/setting.py</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>找到INSTALLED_APPS字段，添加创建的APP，最终如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">INSTALLED_APPS</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;django.contrib.admin&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;django.contrib.auth&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;django.contrib.contenttypes&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;django.contrib.sessions&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;django.contrib.messages&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;django.contrib.staticfiles&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;corsheaders&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;webapi&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="4">
<li><strong>启动项目</strong></li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">python manage.py runserver
</span></span><span class="line"><span class="cl"><span class="c1"># 如果希望除了localhost都能访问启动的时候可以监听所有的ip</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 然后在allow url中填上自己的ip</span>
</span></span><span class="line"><span class="cl">python manager.py runserver 0.0.0.0:8000</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="5">
<li><strong>安装其他依赖项</strong>（启动项目，缺啥就pip install啥，搞定后关掉）</li>
</ol>
<p>如果不需要数据库的话到这里就已经可以了，如果需要数据库的话，我们继续往下看。</p>
<ol start="6">
<li><strong>建立和数据库的连接</strong></li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">vim vuebackend/vuebackend/setting.py</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>​	修改其中的DATABASES字段如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">DATABASES</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;default&#39;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;ENGINE&#39;</span><span class="p">:</span> <span class="s1">&#39;django.db.backends.mysql&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;NAME&#39;</span><span class="p">:</span> <span class="s1">&#39;vuebackend&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;USER&#39;</span><span class="p">:</span> <span class="s1">&#39;root&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;PASSWORD&#39;</span><span class="p">:</span> <span class="s1">&#39;__&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;HOST&#39;</span><span class="p">:</span> <span class="s1">&#39;127.0.0.1&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;PORT&#39;</span><span class="p">:</span> <span class="s1">&#39;3306&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>
<p>ENGINE，如果是mysql的引擎就填这个，别的数据去再去看，</p>
</li>
<li>
<p>NAME：mysql中为后端创建的数据库的名称</p>
</li>
<li>
<p>USER：直接使用root用户，</p>
</li>
<li>
<p>PASSWORD：我们初始化mysql时设置的密码</p>
</li>
<li>
<p>HOST：127.0.0.1 指代本机</p>
</li>
<li>
<p>PORT：3306为mysql默认的启动端口</p>
</li>
</ul>
<ol start="7">
<li><strong>测试数据库功能</strong></li>
</ol>
<p>Django中model.py编写的内容，Django会用其自身的形式进行“包装”（封装），转换成对应的数据库操作，然后在数据库中执行对应的命令。（好像被称作ORM）</p>
<p>而我们主要用到的功能是：创建类，会自动在数据库中生成表格，其中支持的数据类型可以在<a href="https://docs.djangoproject.com/zh-hans/4.1/ref/models/fields/" target="_blank" rel="noopener">官网中找到参考</a>
。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Create your models here.</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Gamerecords</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">    the table for saving abs and the create info
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">m_id</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">AutoField</span><span class="p">(</span><span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">game_name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span> <span class="o">=</span> <span class="mi">150</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">author</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span> <span class="o">=</span> <span class="mi">150</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">file_type</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span> <span class="o">=</span> <span class="mi">150</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s2">&#34;Java&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">create_time</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">DateTimeField</span><span class="p">()</span>   <span class="c1"># 对应python中的Datetime类型</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>定义之后，命令行执行命令，将这些字段映射成数据库中的一张表，下述命令执行数据库操作</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">python manage.py makemigrations <span class="o">(</span>应用名，选填<span class="o">)</span>
</span></span><span class="line"><span class="cl">python manage.py migrate <span class="o">(</span>应用名，选填<span class="o">)</span>
</span></span><span class="line"><span class="cl">python manager.py runserver 启动服务</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>执行完后可以去mysql对应的数据库中，使用show tables查看是否新建表成功。</p>
<p>然后照常启动后端服务。</p>
<p>参考链接：<a href="https://docs.djangoproject.com/zh-hans/4.1/ref/databases/" target="_blank" rel="noopener">offical with mysql</a>
、<a href="https://blog.csdn.net/diligentkong/article/details/79129820" target="_blank" rel="noopener">simple start with mysql</a>
</p>
<ol start="8">
<li>配置跨域便于和vue项目链接：需要安装<code>django-cors-headers</code>模块，并在设置setting.py中导入</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">pip install django-cors-headers</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>然后在项目中添加模块：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># books_demo/settings.py</span>
</span></span><span class="line"><span class="cl"><span class="n">INSTALLED_APPS</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="o">...</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># demo</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;corsheaders&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="o">...</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">MIDDLEWARE</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;corsheaders.middleware.CorsMiddleware&#39;</span><span class="p">,</span> <span class="c1"># 需注意与其他中间件顺序，这里放在最前面即可</span>
</span></span><span class="line"><span class="cl">    <span class="o">...</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 支持跨域配置开始</span>
</span></span><span class="line"><span class="cl"><span class="n">CORS_ORIGIN_ALLOW_ALL</span> <span class="o">=</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl"><span class="n">CORS_ALLOW_CREDENTIALS</span> <span class="o">=</span> <span class="kc">True</span> </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="开发指南">开发指南</h2>
<p>开发界面会基于如下的几个部分进行描述：<strong>前端开发</strong>、<strong>后端开发</strong>、<strong>前后端联通</strong>，每一部分的开发会从一个空项目开始，以现有的代码为例，来介绍各个部分的开发和联通。最后给出一个从0开始设计前端模块、后端功能、前后端传输的Task（demo）。其中也会介绍最raw的debug方式。</p>
<p>一些不错的参考链接：<a href="https://juejin.cn/post/6974565289484615693#heading-3" target="_blank" rel="noopener">前后端从零开始构建流程demo，包含使用curl测试api</a>
、<a href="https://developer.aliyun.com/article/932995" target="_blank" rel="noopener">也是前后端搭建的Demo</a>
</p>
<h2 id="vue和tdesign前端开发">VUE和Tdesign前端开发</h2>
<p>前端部分由于个人能力有限，仅了解到代码结构的大体构筑，和如何修改，因此不做从零开始的参数，仅以自己的认知去介绍如何修改代码，以及各个模块的交互方式介绍。</p>
<p>参考链接：<a href="https://tdesign.tencent.com/starter/docs/vue/custom-config" target="_blank" rel="noopener">页面外观配置</a>
、<a href="https://blog.csdn.net/qq_18671415/article/details/119118905" target="_blank" rel="noopener">vue中引入html界面</a>
</p>
<p><a href="https://tdesign.tencent.com/starter/docs/vue/develop" target="_blank" rel="noopener">必看！！！核心配置，整体的文件逻辑</a>
</p>
<p>具体介绍模块：<strong>代码结构</strong>、<strong>路由结构（如何删除页面的路由，对应的页面在什么地方）</strong>、<strong>页面的简单设计逻辑</strong>、<strong>页面之间的跳转</strong></p>
<p>前端的代码我们基本上只关注<code>src</code>路径下的代码，所有的页面和逻辑基本都在其中：</p>
<p>整体的架构参考上面的链接，我们主要关注的是以下几个文件夹：</p>
<p>page: 存放所有的页面
router： 存放路由跳转逻辑，其中index.js中*定义了默认的主页，其他文件中，定义页面的具体url，<a href="https://tdesign.tencent.com/starter/docs/vue/router-menu" target="_blank" rel="noopener">参考链接</a>
</p>
<h3 id="页面的组成">页面的组成</h3>
<p>可以参考page中的每个文件夹，核心就是：每个index.vue是一个页面。</p>
<p>每个页面基本有三个部分组成：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>vue</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vue" data-lang="vue"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">tempalte</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">	<span class="nx">样式布局</span><span class="err">，</span><span class="nx">也就是基本的外观</span><span class="err">，</span><span class="nx">按钮</span><span class="err">，</span><span class="nx">乱七八糟的</span><span class="err">，</span><span class="nx">去tdesign</span> <span class="nx">vue之类的网站上找模版</span><span class="err">，</span><span class="nx">进行组合即可</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">tempalte</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  <span class="kr">export</span> <span class="k">default</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">data</span>
</span></span><span class="line"><span class="cl">    	<span class="nx">初始化和设置各种变量</span>
</span></span><span class="line"><span class="cl">  	<span class="nx">created</span>
</span></span><span class="line"><span class="cl">    	<span class="nx">里面的函数在页面创建的时候执行</span>
</span></span><span class="line"><span class="cl">  	<span class="nx">mounted</span>
</span></span><span class="line"><span class="cl">  		<span class="nx">里面的函数在页面挂载时候执行</span>
</span></span><span class="line"><span class="cl">		<span class="nx">method</span>
</span></span><span class="line"><span class="cl">  		<span class="nx">定义的各种奇奇怪怪的函数</span><span class="err">，</span><span class="nx">与后端交互的函数</span><span class="err">，</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">定义一些加粗之类的样式</span><span class="err">，</span><span class="nx">用来对template的的基本组件进行加工</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">style</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>其中script中各个部分里面放的函数在不同时候执行：生命周期可以参考https://juejin.cn/post/6874855535234170887，其实就是字面意思，在创建页面之前执行beforecreate啥的（大概意思，具体我也没有太了解）。</p>
<p>method里面就是单纯的函数定义，我们的上传之类的交互代码可以放在这里，然后把函数：</p>
<ol>
<li>绑定到按下按钮等事件上或者</li>
<li>绑定到（放到）某些生命周期中，比如创建页面的时候执行一次，或者页面挂载的时候执行一次之类的</li>
</ol>
<h3 id="页面的跳转结果页跳转之类">页面的跳转（结果页跳转之类）</h3>
<p>我实现的**逻辑（Pipeline）**是这样的：</p>
<p>（前置）跳转到的页面需要再router中注册过 -&gt; 编写一个函数，按下以后跳转到对应的页面，并传递一个id-&gt;跳转到的页面打开的时候读取id，读取数据。</p>
<p><strong>router的注册</strong></p>
<p>在router那个路径，我不确定是path还是name,还是重定向地址，反正调试的时候试试</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>tsx</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-tsx" data-lang="tsx"><span class="line"><span class="cl">	<span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="s2">&#34;path&#34;</span><span class="o">:</span> <span class="s2">&#34;modelbase&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="s2">&#34;name&#34;</span><span class="o">:</span> <span class="s2">&#34;modelbase&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="s2">&#34;component&#34;</span><span class="o">:</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="kr">import</span><span class="p">(</span><span class="s2">&#34;@/pages/list/modelbase/index.vue&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">		<span class="s2">&#34;meta&#34;</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;title&#34;</span><span class="o">:</span> <span class="s2">&#34;上传模型&#34;</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="p">},</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>页面跳转的函数</strong></p>
<p>Router.push就会跳转到对应的页面,name页面名字，query就是传递过去的参数</p>
<p>参考commandtable.vue，row是列表中的参数，代表列表中的某一项，</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl">    <span class="nx">handleClickDetail</span><span class="p">(</span> <span class="nx">row</span> <span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kr">const</span> <span class="nx">m_id_detail</span> <span class="o">=</span> <span class="nx">row</span><span class="p">[</span><span class="s1">&#39;row&#39;</span><span class="p">].</span><span class="nx">m_id</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="k">this</span><span class="p">.</span><span class="nx">$router</span><span class="p">.</span><span class="nx">push</span><span class="p">({</span> <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;modelbase&#39;</span><span class="p">,</span> <span class="nx">query</span><span class="o">:</span> <span class="p">{</span> <span class="nx">ids</span><span class="o">:</span> <span class="nx">m_id_detail</span> <span class="p">}</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>跳转过去的页面加载参数</strong></p>
<p>根据传递过来的参数生成相应的数据用来展示，或者二次跳转？</p>
<p>跳转过去的页面，在生成的生命周期中，使用whtch方法，route传递过来的参数以变化我们就执行下面的函数。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">created</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">$watch</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="k">this</span><span class="p">.</span><span class="nx">$route</span><span class="p">.</span><span class="nx">query</span><span class="p">,</span> <span class="p">(</span><span class="nx">to_params</span><span class="p">,</span> <span class="nx">old_params</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">$route</span><span class="p">.</span><span class="nx">query</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="k">this</span><span class="p">.</span><span class="nx">gettaskinfo</span><span class="p">();</span>  <span class="c1">// your function here  using the route.query中的参数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">$route</span><span class="p">.</span><span class="nx">query</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>然后生成对应的报告之类的</p>
<p>参考文献：<a href="https://blog.csdn.net/weixin_46547740/article/details/109254290" target="_blank" rel="noopener">详情页</a>
</p>
<p>关键词：vue详情页 商品页之类</p>
<h3 id="文件传输前端接口的编写">文件传输前端接口的编写</h3>
<p>该部分的编写依托于<code>elementui</code>或者<code>tdesign</code>的<code>upload</code>组件封装</p>
<p>其基本的编写逻辑如下：</p>
<ul>
<li>
<p><code>action</code>中填写我们编写的后端接口url</p>
</li>
<li>
<p><code>formatResponse</code>中填写对后端返回值的格式处理，用以适应组件识别传输事件是否成功</p>
<ol>
<li>参考 suceess和fail事件的触发条件，用来编写format</li>
<li>tdesign事件是在response中添加url信息和如果失败的话就用error字段传回失败原因</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="k">return</span> <span class="p">{...</span><span class="nx">res</span><span class="p">,</span> <span class="nx">url</span><span class="o">:</span> <span class="nx">xxx</span><span class="p">.</span><span class="nx">xxx</span><span class="p">.</span><span class="nx">xxx</span><span class="p">.</span><span class="nx">xxx</span><span class="o">:</span><span class="nx">xxxx</span><span class="p">,</span> <span class="nx">error</span> <span class="o">:</span> <span class="s2">&#34;why you fail&#34;</span><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>即可在可视化组件上绑定对应的文件上传</p>
</li>
</ul>
<h3 id="静态html页面加载">静态HTML页面加载</h3>
<p>再编写前端页面的时候，有时候需要处理后端生成的html页面，我们希望能够跳转到指定的html文件的。</p>
<ol>
<li>需要将HTML作为静态文件存储到VUE project中静态目录（<code>public</code>）中（防止VUE对HTML文件进行二次编译处理）</li>
<li>假如我们存储的目录为：<code>public/result/index.html</code>我们可以在vue中通过下列函数打开对应页面</li>
</ol>
<p>函数如下:</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">loadLocalHtml</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">  <span class="nx">windows</span><span class="p">.</span><span class="nx">open</span><span class="p">(</span><span class="s1">&#39;/result/index.html&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果需要灵活加载详情页面，我们可以根据传入的参数来确定最后存储的地址（或者在后端对文件进行移动）</p>
<h3 id="前后端的联通">前后端的联通</h3>
<p>同样也是在mehtod中定义一个访问接口的方法，然后在合适的时候调用这个访问接口的函数就行。放在下面的前后端联动的部分</p>
<h2 id="django后端开发">Django后端开发</h2>
<p>实现基础功能的话，后端的逻辑和实现相对较为简单，本文介绍：开发api的流程（将自己的功能嵌入）、提供对数据库进行<strong>增删改查</strong>的例子、提供<strong>文件传输</strong>api的例子。文件传输好像有更优的解法，后续进行更新</p>
<p><strong>后端开发Pipeline</strong></p>
<p>（optional）<code>model.py</code>设计数据表 -&gt; <code>view</code>中设计api（数据获取，数据上传等任何功能）-&gt;注册api到特定的url-&gt;测试api-&gt;done.</p>
<ol>
<li>如果有数据库需求才使用，可以简单的存储（用户，时间，存储html路径，语言类型，项目名称等）</li>
<li>view中有特定的八股文，下面为会讲到特定的<code>&lt;func&gt;</code>占位部分，填入自己的功能，实现：**根据传来的数据或者GET请求，执行特定的操作，返回特定信息（不返回也行）**的流程即可。</li>
<li>将该域名注册个特定的api，便于访问该api</li>
</ol>
<h3 id="数据表设计">数据表设计</h3>
<p>参考上述的例子（环境配置-Django-6数据库测试），在<code>model.py</code>文件中创建一个类，定义需要的表结构，然后执行两部数据库操作即可：</p>
<p>下面给出一个Coverage-Test的上传信息类设计Demo：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">Class</span> <span class="n">CoverageInfo</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">  <span class="n">m_id</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">AutoField</span><span class="p">(</span><span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">task_name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span> <span class="o">=</span> <span class="mi">150</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="s2">&#34;coverage test&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">author</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span> <span class="o">=</span> <span class="mi">150</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="s2">&#34;anmous&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">create_time</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">DateTimeField</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="n">lang_type</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span> <span class="o">=</span> <span class="mi">150</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="s2">&#34;JAVA&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">res_path</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span> <span class="o">=</span> <span class="mi">1000</span><span class="p">,</span> <span class="n">defailt</span> <span class="o">=</span> <span class="s2">&#34;~/workspace/coverage-res/author_default/&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">code_path</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span> <span class="o">=</span> <span class="mi">1000</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="s1">&#39;~/workspace/coverage-code/author_default/&#39;</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>该Table的处理逻辑如下：</p>
<ul>
<li>task_name、author、lang_type交由前端用户填写，传递到后端；</li>
<li>m_id为mysql自动递增的数据逻辑我们无需处理，create_time在后端接受请求的时候自动计算</li>
<li>res_path在执行完覆盖率测试后，将文件存储指定定地点，然后将该地点返回，将该地点存进数据库，这样我们就可以随时查询任一个记录的覆盖率结果。</li>
</ul>
<p>将这些信息存入数据库，便于增删改查，文件和结果则存储本地。</p>
<p><strong>mysql中生成表</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">python manage.py makemigrations 
</span></span><span class="line"><span class="cl">python manage.py migrate</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="api设计">API设计</h3>
<p>主要从前端接受两种请求：GET、POST，然后基于这两种请求，我们实现对数据增删改查的操作，或者其他的特定操作。API的定义在<code>views.py</code>中完成。基础的范式如下：</p>
<p>需要注意的是，前后端之间的数据传输，基本都是约定为JSON这种KEY-VALUE格式的，故而我们好像需要进行什么序列化反序列化的操作，来对信息进行解读（理论后续补充）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">django.http</span> <span class="kn">import</span> <span class="n">JsonResponse</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">django.views.decorators.http</span> <span class="kn">import</span> <span class="n">require_http_methods</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">django.core</span> <span class="kn">import</span> <span class="n">serializers</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@require_http_methods</span><span class="p">([</span><span class="s1">&#39;GET&#39;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_games_index</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">response</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">      <span class="c1"># using get to get value from front ----&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="n">receive</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">      <span class="n">reveive</span><span class="p">[</span><span class="s1">&#39;info1&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">GET</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;info1&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="o">...</span> <span class="c1"># like that ， 应该也可以循环取出</span>
</span></span><span class="line"><span class="cl">      <span class="c1"># &lt;----- using get to get value from front </span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">      <span class="c1"># your function here 「-----------------</span>
</span></span><span class="line"><span class="cl">      <span class="c1"># 基于我们从前端获取到的数据，做任何事情，执行任何函数</span>
</span></span><span class="line"><span class="cl">      <span class="c1"># -------------- your function here 」</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">      <span class="c1"># 可以给前端返回一些数据 response[&#39;res&#39;] = ... 之类的,传过去之前要对数据进行序列话处理</span>
</span></span><span class="line"><span class="cl">      <span class="c1"># yourdata需要时{}存kv形式</span>
</span></span><span class="line"><span class="cl">      <span class="n">response</span><span class="p">[</span><span class="s1">&#39;res&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">serializers</span><span class="o">.</span><span class="n">serialize</span><span class="p">(</span><span class="s2">&#34;json&#34;</span><span class="p">,</span> <span class="n">yourdata</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">      <span class="n">response</span><span class="p">[</span><span class="s1">&#39;msg&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;success&#39;</span>
</span></span><span class="line"><span class="cl">      <span class="n">response</span><span class="p">[</span><span class="s1">&#39;error_num&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      <span class="n">response</span><span class="p">[</span><span class="s1">&#39;msg&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">response</span><span class="p">[</span><span class="s1">&#39;error_num&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="n">JsonResponse</span><span class="p">(</span><span class="n">response</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>（带文件的post会比较特殊，后面在例子里面单独讲）POST例子和GET例子主要的区别在于：获取传递过来的数据的方式不同，注意这里的JSON.loads。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nd">@require_http_methods</span><span class="p">([</span><span class="s2">&#34;POST&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_info_games</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">      <span class="n">response</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">      <span class="c1"># 获取前端post过来的文件什么的</span>
</span></span><span class="line"><span class="cl">      <span class="n">post_message</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">body</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="c1"># 获取前端post过来的参数什么的还是使用get</span>
</span></span><span class="line"><span class="cl">      <span class="n">reveive</span><span class="p">[</span><span class="s1">&#39;params&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">GET</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;params&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">      <span class="n">games</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">serializers</span><span class="o">.</span><span class="n">serialize</span><span class="p">(</span><span class="s2">&#34;json&#34;</span><span class="p">,</span> <span class="n">games</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">      <span class="n">response</span><span class="p">[</span><span class="s1">&#39;games&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">games</span>
</span></span><span class="line"><span class="cl">      <span class="n">response</span><span class="p">[</span><span class="s1">&#39;mag&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;success&#39;</span>
</span></span><span class="line"><span class="cl">      <span class="n">response</span><span class="p">[</span><span class="s1">&#39;error_num&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      <span class="n">response</span><span class="p">[</span><span class="s1">&#39;msg&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">response</span><span class="p">[</span><span class="s1">&#39;error_num&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="n">JsonResponse</span><span class="p">(</span><span class="n">response</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="增删改查demo">增删改查demo</h4>
<p>以上述设计的coverage_test表格为例子，“增删改查”实际上都是对数据库进行的操作，因此实际上的操作范例都较为相似，下面废话不多说，直接给出demo进行讲解。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 增：实际上就是获取数据（post），将数据存储进数据库中，所以我们首先使用post协议，在根据上述的八股文，用json.load(request.body)获取post传过来的数据，其表现为字典的形式。</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 由于文件传输的类型是2进制数据流，没办法用json load，所以和普通的post处理比较不同，我们后面讲，这里先讲基本的post。</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">models</span> <span class="kn">import</span> <span class="n">CoverageInfo</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@require_http_methods</span><span class="p">([</span><span class="s2">&#34;POST&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">update_task</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">response</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">post_message</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">body</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># print(post_message)</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 讲数据存进我们定义的类结构中。</span>
</span></span><span class="line"><span class="cl">        <span class="n">tasks</span> <span class="o">=</span> <span class="n">CoverageInfo</span><span class="p">(</span><span class="n">task_name</span> <span class="o">=</span> <span class="n">post_message</span><span class="p">[</span><span class="s1">&#39;task_name&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">                            <span class="n">author</span> <span class="o">=</span> <span class="n">post_message</span><span class="p">[</span><span class="s1">&#39;author&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">                            <span class="n">lang_type</span> <span class="o">=</span> <span class="n">post_message</span><span class="p">[</span><span class="s1">&#39;lang_type&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">                            <span class="n">create_time</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">                            <span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 使用save命令将其存进数据库中</span>
</span></span><span class="line"><span class="cl">        <span class="n">task</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">#可以返回一下我们存储起来的数据</span>
</span></span><span class="line"><span class="cl">        <span class="n">response</span><span class="p">[</span><span class="s1">&#39;task&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">serializers</span><span class="o">.</span><span class="n">serialize</span><span class="p">(</span><span class="s2">&#34;json&#34;</span><span class="p">,</span> <span class="n">games</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">response</span><span class="p">[</span><span class="s1">&#39;mag&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;success&#39;</span>
</span></span><span class="line"><span class="cl">        <span class="n">response</span><span class="p">[</span><span class="s1">&#39;error_num&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">response</span><span class="p">[</span><span class="s1">&#39;msg&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">response</span><span class="p">[</span><span class="s1">&#39;error_num&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">JsonResponse</span><span class="p">(</span><span class="n">response</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>删除/修改/查询，实际上是类似的，都是先找到然后再进行操作，这里一并讲了</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 显示近期的5个task</span>
</span></span><span class="line"><span class="cl"><span class="nd">@require_http_methods</span><span class="p">([</span><span class="s1">&#39;GET&#39;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">recent_tasks</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">response</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">    <span class="n">num_to_show</span> <span class="o">=</span> <span class="mi">5</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      	<span class="c1"># .objects.filter()会返回符合filter条件的所有记录，如果是空的就会返回所有</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 所以删，改，查，就是从前端传递一个id回来，然后我们用filter找到他，然后print、覆盖、删除。</span>
</span></span><span class="line"><span class="cl">        <span class="n">tasks</span> <span class="o">=</span> <span class="n">CoverageInfo</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="n">response</span><span class="p">[</span><span class="s1">&#39;tasks&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">serializers</span><span class="o">.</span><span class="n">serialize</span><span class="p">(</span><span class="s2">&#34;json&#34;</span><span class="p">,</span> <span class="n">models</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="n">response</span><span class="p">[</span><span class="s1">&#39;tasks&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s1">&#39;tasks&#39;</span><span class="p">][</span><span class="o">-</span><span class="n">num_to_show</span><span class="p">:]</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># print(response[&#39;models&#39;])</span>
</span></span><span class="line"><span class="cl">        <span class="n">response</span><span class="p">[</span><span class="s1">&#39;msg&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;success&#39;</span>
</span></span><span class="line"><span class="cl">        <span class="n">response</span><span class="p">[</span><span class="s1">&#39;error_num&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">response</span><span class="p">[</span><span class="s1">&#39;msg&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">response</span><span class="p">[</span><span class="s1">&#39;error_num&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">JsonResponse</span><span class="p">(</span><span class="n">response</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>删、改、查，（使用get方法用参数来找到就行了）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nd">@require_http_methods</span><span class="p">([</span><span class="s2">&#34;GET&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">delete_models</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">response</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">        <span class="n">get_id</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">GET</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;ID&#34;</span><span class="p">)</span> <span class="c1"># ID是在前端定义好的传回来的key，随便定啥都行</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 查询</span>
</span></span><span class="line"><span class="cl">        <span class="n">results</span> <span class="o">=</span> <span class="n">CoverageInfo</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">m_id</span> <span class="o">=</span> <span class="n">get_id</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 删除</span>
</span></span><span class="line"><span class="cl">        <span class="n">CoverageInfo</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">m_id</span><span class="o">=</span><span class="n">get_id</span><span class="p">)</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 修改（基于查询那一步）</span>
</span></span><span class="line"><span class="cl">        <span class="n">results</span><span class="o">.</span><span class="n">author</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">GET</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;Author&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="o">...</span> <span class="c1"># 重复操作每一条属性</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="n">response</span><span class="p">[</span><span class="s1">&#39;mag&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;success&#39;</span>
</span></span><span class="line"><span class="cl">        <span class="n">response</span><span class="p">[</span><span class="s1">&#39;error_num&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">response</span><span class="p">[</span><span class="s1">&#39;msg&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">response</span><span class="p">[</span><span class="s1">&#39;error_num&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">JsonResponse</span><span class="p">(</span><span class="n">response</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="文件接受api-demo">文件接受API demo</h4>
<p>由于我这边还没有完全掌握文件传输的方法，这里我的实现会和基本的post方法获取有一点区分，下面讲解文件传输的后端操作：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nd">@require_http_methods</span><span class="p">([</span><span class="s1">&#39;POST&#39;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">accept_code_file</span><span class="p">(</span><span class="n">request</span><span class="p">):</span> <span class="c1"># 原版test_api</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">response</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># （存在本地）定义一个存储文件的基本地址，（本地先新建这个目录）</span>
</span></span><span class="line"><span class="cl">    <span class="n">base_path</span> <span class="o">=</span> <span class="s2">&#34;/data/home/metis/workspace/code_file&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      	<span class="c1"># 用作者名来管理文件的存储地址</span>
</span></span><span class="line"><span class="cl">        <span class="n">author_name</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">GET</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;author&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="ow">not</span> <span class="n">author_name</span><span class="p">:</span> 
</span></span><span class="line"><span class="cl">            <span class="n">author_name</span> <span class="o">=</span> <span class="s1">&#39;tmp&#39;</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 把地址和提交者名拼起来，没有的话新建文件夹</span>
</span></span><span class="line"><span class="cl">        <span class="n">real_path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">base_path</span><span class="p">,</span> <span class="n">author_name</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">real_path</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">os</span><span class="o">.</span><span class="n">mkdir</span><span class="p">(</span><span class="n">real_path</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1"># 循环存储传过来的所有文件</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">filename</span><span class="p">,</span> <span class="n">file</span> <span class="ow">in</span> <span class="n">request</span><span class="o">.</span><span class="n">FILES</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">            <span class="nb">print</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">file</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">tmp</span> <span class="o">=</span> <span class="n">file</span><span class="o">.</span><span class="n">read</span><span class="p">()</span> <span class="c1"># 文件的二进制数据流，也就是实际要存下来的数据</span>
</span></span><span class="line"><span class="cl">            <span class="n">newfilename</span> <span class="o">=</span> <span class="n">random_filename</span><span class="p">(</span><span class="n">file</span><span class="o">.</span><span class="n">name</span><span class="p">)</span> <span class="c1"># 可以对文件名进行简单的处理</span>
</span></span><span class="line"><span class="cl">            <span class="n">final_path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">real_path</span><span class="p">,</span> <span class="n">newfilename</span><span class="p">)</span> <span class="c1"># 拼接地址</span>
</span></span><span class="line"><span class="cl">            <span class="nb">print</span><span class="p">(</span><span class="n">final_path</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="c1"># 讲文件存起来(使用chunk便于大文件的断点续传，避免大文件传输出现问题)</span>
</span></span><span class="line"><span class="cl">            <span class="c1"># (TBD) 测试验证是否正确 （可能需要使用request.FILES[&#39;file&#39;]替代后面的file.chunks）</span>
</span></span><span class="line"><span class="cl">            <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">final_path</span><span class="p">,</span> <span class="s1">&#39;wb&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="k">for</span> <span class="n">chunk</span> <span class="ow">in</span> <span class="n">file</span><span class="o">.</span><span class="n">chunks</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">                  <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">chunk</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="c1"># 小文件传输的例子</span>
</span></span><span class="line"><span class="cl">            <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">final_path</span><span class="p">,</span> <span class="s1">&#39;wb&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">             		<span class="n">f</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">tmp</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                 
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1"># 获取代码的类型,执行对应的代码,生成html文件,返回文件的地址</span>
</span></span><span class="line"><span class="cl">        <span class="n">lang_type</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">GET</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;lang_type&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 逻辑是这样，如果处理覆盖率的时间比较长，可能要在后台跑，这个研究下怎么处理。</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 关键词 Django后台、Django多线程、还没查好，先放一些参考资料，可能就是用一个线程来执行任务</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># https://www.tioit.cc/index.php/archives/6/</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># https://zhuaxia.xyz/detail/11847</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="n">html_path</span> <span class="o">=</span> <span class="n">coverage_test</span><span class="p">(</span><span class="n">final_path</span><span class="p">,</span> <span class="n">lang_type</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1"># 建立数据库词条，可以新增一条代码存储的路径(数据)</span>
</span></span><span class="line"><span class="cl">        <span class="n">tasks</span> <span class="o">=</span> <span class="n">CoverageInfo</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">          									<span class="n">task_name</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">GET</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;task_name&#39;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">                            <span class="n">author</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">GET</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;author&#39;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">                            <span class="n">lang_type</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">GET</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;lang_type&#39;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">                            <span class="n">create_time</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">                            <span class="n">res_path</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">GET</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;html_path&#39;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">          									<span class="n">code_path</span> <span class="o">=</span> <span class="n">final_path</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                            <span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">task</span><span class="o">.</span><span class="n">save</span><span class="p">()</span> <span class="c1"># 将词条存进数据库里。</span>
</span></span><span class="line"><span class="cl">        <span class="n">response</span><span class="p">[</span><span class="s1">&#39;task&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">serializers</span><span class="o">.</span><span class="n">serialize</span><span class="p">(</span><span class="s2">&#34;json&#34;</span><span class="p">,</span> <span class="n">tasks</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="n">response</span><span class="p">[</span><span class="s1">&#39;msg&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;success&#39;</span>
</span></span><span class="line"><span class="cl">        <span class="n">response</span><span class="p">[</span><span class="s1">&#39;error_num&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">response</span><span class="p">[</span><span class="s1">&#39;msg&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">response</span><span class="p">[</span><span class="s1">&#39;error_num&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">JsonResponse</span><span class="p">(</span><span class="n">response</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>注意pipeline</strong>写完接口后要去注册url。</p>
<h3 id="api注册">API注册</h3>
<p>首先将我们的所有api都注册到/api/（可以自己改） 下面：在项目（vuebackend）的<code>urls.py</code>配置文件（这个可能是自己生成或者默认的）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="s2">&#34;&#34;&#34;vuebackend URL Configuration
</span></span></span><span class="line"><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="cl"><span class="s2">The `urlpatterns` list routes URLs to views. For more information please see:
</span></span></span><span class="line"><span class="cl"><span class="s2">    https://docs.djangoproject.com/en/3.2/topics/http/urls/
</span></span></span><span class="line"><span class="cl"><span class="s2">Examples:
</span></span></span><span class="line"><span class="cl"><span class="s2">Function views
</span></span></span><span class="line"><span class="cl"><span class="s2">    1. Add an import:  from my_app import views
</span></span></span><span class="line"><span class="cl"><span class="s2">    2. Add a URL to urlpatterns:  path(&#39;&#39;, views.home, name=&#39;home&#39;)
</span></span></span><span class="line"><span class="cl"><span class="s2">Class-based views
</span></span></span><span class="line"><span class="cl"><span class="s2">    1. Add an import:  from other_app.views import Home
</span></span></span><span class="line"><span class="cl"><span class="s2">    2. Add a URL to urlpatterns:  path(&#39;&#39;, Home.as_view(), name=&#39;home&#39;)
</span></span></span><span class="line"><span class="cl"><span class="s2">Including another URLconf
</span></span></span><span class="line"><span class="cl"><span class="s2">    1. Import the include() function: from django.urls import include, path
</span></span></span><span class="line"><span class="cl"><span class="s2">    2. Add a URL to urlpatterns:  path(&#39;blog/&#39;, include(&#39;blog.urls&#39;))
</span></span></span><span class="line"><span class="cl"><span class="s2">&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">from django.contrib import admin
</span></span><span class="line"><span class="cl">from django.urls import path, include
</span></span><span class="line"><span class="cl">import vueapi.urls
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">urlpatterns</span> <span class="o">=</span> <span class="o">[</span>
</span></span><span class="line"><span class="cl">    path<span class="o">(</span><span class="s1">&#39;admin/&#39;</span>, admin.site.urls<span class="o">)</span>,
</span></span><span class="line"><span class="cl">    path<span class="o">(</span><span class="s1">&#39;api/&#39;</span>, include<span class="o">(</span>vueapi.urls<span class="o">))</span>,   <span class="c1"># 改这里可以了（就初始化的时候改一下就行）</span>
</span></span><span class="line"><span class="cl"><span class="o">]</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>然后注册我们的每个API具体的地址<code>/api/&lt;specifal&gt;</code>中</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># from django.urls import path, re_path</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">django.urls</span> <span class="kn">import</span> <span class="n">re_path</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">.</span> <span class="kn">import</span> <span class="n">views</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">urlpatterns</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="n">re_path</span><span class="p">(</span><span class="sa">r</span><span class="s1">&#39;accept_code_file$&#39;</span><span class="p">,</span> <span class="n">views</span><span class="o">.</span><span class="n">accept_code_file</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl"><span class="p">]</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>注册完成后可以用curl命令测试api</p>
<p><strong>命令行使用curl命令测试API</strong></p>
<ol>
<li>测试get</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl  http://127.0.0.1:8000/api/&lt;api_name&gt;?&lt;key&gt;<span class="o">=</span>&lt;value&gt;</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><code>&lt;api&gt;</code> 填我们在django的后端中注册的名字、key-value的形式输入我们传入后端的数据。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl http://127.0.0.1:8000/api/accept_code_file?author<span class="o">=</span>aiken<span class="p">&amp;</span><span class="nv">task_name</span><span class="o">=</span>test</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="2">
<li>测试post</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -d <span class="s2">&#34;Key=Value&#34;</span> <span class="s1">&#39;http://127.0.0.1:8000/api/accept_code_file?author=aiken7task_name=test&#39;</span> </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>-d后面是post获取的</p>
<p>？后面是get获取的</p>
<h2 id="前后端联动">前后端联动</h2>
<p>该部分主要从这几个部分开始介绍：<strong>Get请求后端操作返回数据</strong>、<strong>Post传输数据给后端并接受返回值</strong>、<strong>Debug方式</strong>、具体demo（文件传输、数据的增删改查、最近的数据显示）。</p>
<p>前后端进行接口的交互主要是前端基于<a href="http://axios-js.com/zh-cn/docs/index.html" target="_blank" rel="noopener">axios</a>
这个模块向后端发送请求的（文件传输我用的这个写法），在<a href="https://tdesign.tencent.com/starter/docs/vue/request-data" target="_blank" rel="noopener">tdesign</a>
中还封装了一种形式，好像也是基于axios封装的（其他的我都用的这种写法）</p>
<p>这一部分方法都在method（）中定义，然后在需要的地方定义，通常为更新data中的数据，</p>
<h3 id="发起一个get请求">发起一个Get请求</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl">    <span class="nx">getModelList</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">this</span><span class="p">.</span><span class="nx">$request</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;http://9.134.13.0:8000/api/recent_models&#39;</span><span class="p">)</span>  <span class="err">#</span> <span class="nx">url</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">then</span><span class="p">((</span><span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>                                  <span class="err">#</span> <span class="nx">前端返回的数据在res中</span>
</span></span><span class="line"><span class="cl">          <span class="kr">const</span> <span class="nx">m_model_list</span> <span class="o">=</span> <span class="nx">res</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">models</span><span class="p">;</span>           
</span></span><span class="line"><span class="cl">          <span class="err">#</span> <span class="nx">通过</span> <span class="nx">res</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="o">&lt;</span><span class="nx">key</span><span class="o">&gt;</span><span class="nx">的方式取出数据</span><span class="err">，</span><span class="nx">就是我们返回的一整个json</span>
</span></span><span class="line"><span class="cl">          <span class="nx">看前端的console</span><span class="p">.</span><span class="nx">log打印出来的值</span><span class="err">，</span><span class="nx">可以知道其是一个列表形式的</span><span class="err">，</span><span class="nx">而我们返回值是列表中的list</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">field</span><span class="p">.</span><span class="nx">将其存进临时的列表中</span>
</span></span><span class="line"><span class="cl">          <span class="kr">const</span> <span class="nx">m_list_test</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">          <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">m_model_list</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="o">++</span><span class="nx">i</span><span class="p">){</span>  
</span></span><span class="line"><span class="cl">            <span class="nx">m_list_test</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">m_model_list</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">fields</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">          <span class="p">}</span>
</span></span><span class="line"><span class="cl">          <span class="err">#</span> <span class="nx">this取全局变量</span><span class="err">，</span><span class="nx">在data中定义好的</span><span class="err">，</span><span class="nx">我们更新这个值用来渲染数据</span>
</span></span><span class="line"><span class="cl">          <span class="k">this</span><span class="p">.</span><span class="nx">model_list</span> <span class="o">=</span> <span class="nx">m_list_test</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">          <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">model_list</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">})</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="k">catch</span><span class="p">((</span><span class="nx">e</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="发起一个post请求">发起一个POST请求</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl">    <span class="nx">getGameInfo</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;start&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">this</span><span class="p">.</span><span class="nx">$request</span>
</span></span><span class="line"><span class="cl">      	 <span class="c1">// 将上个路由界面穿过来的id作为参数，传到后端去，然后请求后端返回特定的数据
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s1">&#39;http://9.134.13.0:8000/api/get_info_games&#39;</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">$route</span><span class="p">.</span><span class="nx">query</span><span class="p">[</span><span class="s1">&#39;ids&#39;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">then</span><span class="p">((</span><span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="kr">const</span> <span class="nx">task_list</span> <span class="o">=</span> <span class="nx">res</span><span class="p">.</span><span class="nx">data</span><span class="p">.</span><span class="nx">games</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">fields</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">          <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">res</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">          <span class="kr">const</span> <span class="nx">m_list_res</span> <span class="o">=</span> <span class="nb">Array</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">          <span class="c1">// 赋值变量
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>          <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">key</span> <span class="k">in</span> <span class="nx">task_list</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">m_list_res</span><span class="p">.</span><span class="nx">push</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">              <span class="nx">name</span><span class="o">:</span> <span class="nx">key</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nx">value</span><span class="o">:</span> <span class="nx">task_list</span><span class="p">[</span><span class="nx">key</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="p">})</span>
</span></span><span class="line"><span class="cl">          <span class="p">}</span>
</span></span><span class="line"><span class="cl">          <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">m_list_res</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">          <span class="c1">// 赋值全局变量
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>          <span class="k">this</span><span class="p">.</span><span class="nx">baseInfoData</span> <span class="o">=</span> <span class="nx">m_list_res</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="p">})</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="k">catch</span><span class="p">((</span><span class="nx">e</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="文件传输的特殊post请求">文件传输的特殊POST请求</h3>
<p>普通的post</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl">    <span class="nx">onSubmitPost</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;submit! post&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="k">this</span><span class="p">.</span><span class="nx">$request</span>
</span></span><span class="line"><span class="cl">      	<span class="c1">// 将全局参数中的formdata用post传递到后端，接受后端返回到信息
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s2">&#34;http://9.134.13.0:8000/api/create_battel&#34;</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">formData</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">then</span><span class="p">((</span><span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">res</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">          <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;---------------------------&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">          <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">formData</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">        <span class="p">})</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="k">catch</span><span class="p">((</span><span class="nx">e</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">          <span class="nx">alert</span><span class="p">(</span><span class="s1">&#39; create battel fail&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>对应页面跳转的post</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl">    <span class="nx">submit_file</span><span class="p">(</span><span class="nx">file</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">file</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="c1">// 获取文件到临时的变量formdatas中
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>      <span class="kd">let</span> <span class="nx">formdatas</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">FormData</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">      <span class="nx">formdatas</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="s1">&#39;file&#39;</span><span class="p">,</span> <span class="nx">file</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">formData</span><span class="p">.</span><span class="nx">author</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="nx">axios</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">        <span class="nx">url</span><span class="o">:</span> <span class="s1">&#39;http://9.134.13.0:8000/api/test_api&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">method</span><span class="o">:</span> <span class="s1">&#39;post&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">headers</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="s1">&#39;Content-Type&#39;</span><span class="o">:</span> <span class="s1">&#39;multipart/form-data&#39;</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// data传递文件数据 params传递参数数据
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="nx">data</span><span class="o">:</span> <span class="nx">formdatas</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">params</span><span class="o">:</span> <span class="p">{</span> <span class="s1">&#39;author&#39;</span><span class="o">:</span> <span class="k">this</span><span class="p">.</span><span class="nx">formData</span><span class="p">.</span><span class="nx">author</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">      <span class="p">}).</span><span class="nx">then</span><span class="p">((</span><span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">res</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">$message</span><span class="p">.</span><span class="nx">success</span><span class="p">(</span><span class="sb">`文件 </span><span class="si">${</span><span class="nx">file</span><span class="p">.</span><span class="nx">name</span><span class="si">}</span><span class="sb"> 上传成功`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="p">}).</span><span class="k">finally</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// this.handleSuccess();
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>      <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="debug">Debug</h2>
<p><strong>首先介绍简单的变更查看方式，方便知道别人在基础的项目上做了啥改动</strong></p>
<ol>
<li>
<p>借助VsCode和Git，安装git，vscode，vscode的git插件</p>
</li>
<li>
<p>初始化一个项目（无论是Django还是vue还是任何其他）</p>
</li>
<li>
<p>git init，git add，git commit 提交一次原始版本</p>
</li>
<li>
<p>将别人的代码文件拖进来覆盖掉，即可在vscode边栏中的git项目管理中，看到与上次提交的不同，从而看出别人有多少改变，借助该工具也能轻松的还原回原始的样子。</p>
</li>
</ol>
<p>（该指令是基于git diff的，但是在命令行中没有那么易于查看，因此借助vscode，git diff也可以了解一下）</p>
<p><strong>node重新安装依赖包</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">rm -rv node_modules <span class="c1"># del those files we downlaods</span>
</span></span><span class="line"><span class="cl">rm package-lock.json <span class="c1"># del the install info </span>
</span></span><span class="line"><span class="cl">npm cache clear --force
</span></span><span class="line"><span class="cl">npm install</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>NPM中包的安装路径</strong></p>
<p>节选自参考链接<a href="https://cloud.tencent.com/developer/article/1834667" target="_blank" rel="noopener">Link</a>
</p>
<ol>
<li>本地安装 <code>npm install</code> 安装到当前路径的node_modules中</li>
<li>全局安装添加<code>-g</code>参数</li>
</ol>
<p>全局文件的安装地址在: <code>npm root -g </code></p>

  </div>
</div>

<script>
    


function sanitizeContent(content) {
    
    return content.replace(/[\x00-\x1F\x7F]/g, '').trim(); 
}

function encryptContent(password, content) {
    const key = CryptoJS.MD5(password).toString();
    const iv = key.substring(16); 
    const paddedContent = padContent(content);
    const encrypted = CryptoJS.AES.encrypt(paddedContent, CryptoJS.enc.Utf8.parse(key), {
        iv: CryptoJS.enc.Utf8.parse(iv),
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
}

function padContent(content) {
    const blockSize = 32; 
    const padlen = blockSize - (content.length % blockSize);
    
    
    return content;
}

function processEncryptedBlocks() {
    const blocks = document.querySelectorAll('.hugo-encryptor-cipher-text');
    blocks.forEach(block => {
        const password = block.getAttribute('data-password');
        const content = block.innerHTML.trim(); 
        const sanitizedContent = sanitizeContent(content); 
        const encryptedContent = encryptContent(password, sanitizedContent);
        block.innerHTML = encryptedContent;
        block.removeAttribute('data-password');
    });

    
    const script = document.createElement('script');
    script.src = '/js/decrypt.js';
    document.body.appendChild(script);
}


document.addEventListener('DOMContentLoaded', processEncryptedBlocks);
</script>
]]></content:encoded>
    </item>
    <item>
      <title>MacOS 的软件安装和系统设置</title>
      <link>https://aikenh.cn/posts/macos/</link>
      <pubDate>Sat, 10 Sep 2022 00:00:00 +0000</pubDate>
      <guid>https://aikenh.cn/posts/macos/</guid>
      <description>this Configuration focus on the terminal functionality.</description>
      <content:encoded><![CDATA[<p>配置一台全新的 MacOs（M1）用于日常使用和编程开发，这里总结一下自己体验比较好的 APP 和开发工具。Let‘s Go</p>
<h2 id="系统基础设置">系统基础设置</h2>
<p><strong>调转 F 区功能</strong>：在涉及到开发的时候，F 区很多情况下就会派上用场，因此这里简单介绍一下：</p>
<ul>
<li>系统设置里搜索&quot;功能键&quot;</li>
<li>在弹出页面中选择将 F 1 作为标准功能键勾选即可</li>
</ul>
<p><strong>触控板功能</strong>：特别是三指拖动功能一定要开启，用来拖放窗口和文件方便太多。</p>
<ul>
<li>系统偏好设置 -&gt; 触控板 -&gt; 三指点按查询</li>
<li>系统偏好设置 -&gt; 辅助功能 -&gt; 指针控制-&gt; 触控板选项 -&gt; 三指拖动</li>
</ul>
<p><strong>访达设置：</strong></p>
<p>首先在偏好设置中有以下的几个可以调整：</p>
<ul>
<li>通用 -&gt; 开启新访达窗口时打开</li>
<li>高级 -&gt; 显示文件拓展名</li>
<li>边栏 -&gt; 选择自己想要的边栏</li>
</ul>
<p>接着是在显示选线卡中，可以勾选：“显示路径栏”、“‘显示状态栏’”</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230402164844.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230402164844.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230402164844.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="用-raycast-替换-spotlight">用 Raycast 替换 Spotlight</h3>
<p>MacOS 中的 Spotlight 是一个很棒的设计，在某些程度上弥补了其资源管理器和应用设计上的缺陷，提高了很大的便利性（Windows 上可以基于 PowerToy 来补全该功能），但是许多第三方的 Spotlight 都比官方好用，这里我推荐免费的 raycast。</p>
<p>raycast 由于其插件支持的特性，能够玩出很多花样，同时其基本的功能也相当的强大，完全可以作为原生的上位替代，因此建议直接关闭原生。</p>
<ul>
<li>系统设置中搜索 spotlight-&gt;键盘-&gt;键盘快捷键</li>
<li>聚焦-&gt;关闭</li>
</ul>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230402174110.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230402174110.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230402174110.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>


<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230402174214.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230402174214.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20230402174214.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>然后在 raycast 中将快捷键设置为 Command +SPC 即可，其也支持剪切板历史记录功能，因此后续没有推荐相关的应用了。</p>
<h3 id="将-edge-设置为默认浏览器">将 Edge 设置为默认浏览器</h3>
<p>虽然原生的 safari 有着不错的颜值，但是从外观，性能，功能，以及多设备协同中，我个人还是比较推崇 Edge，认为其在大部分平台目前都是我的第一选择。</p>
<p>Edge -&gt; 首选项 -&gt; 默认浏览器 -&gt; 设置为默认浏览器</p>
<h3 id="选择自己喜欢的壁纸">选择自己喜欢的壁纸</h3>
<p>这里可以选择动态的壁纸，也就是随着时间变化的类型，其实只是一种特殊的文件格式，使用其作为壁纸就能实现对应的效果，所以我们下载好对应的动态壁纸格式就行：</p>
<ul>
<li><a href="https://dynamicwallpaper.club/wallpaper/7v33v1oit8n" target="_blank" rel="noopener">Dynamic 1</a>
</li>
<li><a href="http://dynwalls.com/index.html" target="_blank" rel="noopener">Dynamic 2</a>
</li>
</ul>
<p>由于 Mac 本身过硬的屏幕质量，其他的最好4 k 及以上的壁纸，效果会更好，这里给出一些壁纸下载的链接：</p>
<ol>
<li><a href="https://wallpaperhub.app" target="_blank" rel="noopener">Microsoft Wallpaper</a>
</li>
<li><a href="https://www.pexels.com/search/mac%20wallpaper/" target="_blank" rel="noopener">Pixels</a>
</li>
<li><a href="https://unsplash.com/wallpapers/desktop/mac" target="_blank" rel="noopener">Unsplash</a>
</li>
</ol>
<h2 id="软件安装和配置">软件安装和配置</h2>
<p>首先来个省流总结图如下，个人<strong>必装</strong>的一些软件，大多都是无需什么配置开箱即用的，有一些需要个性化设置的后续可能会专门开文介绍下自己的方案。</p>
<table>
  <thead>
      <tr>
          <th>APP</th>
          <th>Type</th>
          <th>Desc</th>
          <th>Recommend</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Clash X</td>
          <td>Proxy</td>
          <td>开发环境配置的时候有一个总没错</td>
          <td>🔥🔥🔥</td>
      </tr>
      <tr>
          <td>Edge</td>
          <td>Browser</td>
          <td>用微软账号同步多设备、OS；全面</td>
          <td>🔥🔥🔥</td>
      </tr>
      <tr>
          <td>搜狗输入法</td>
          <td>sys-Enhance</td>
          <td>Macos 自带的实在是太难用了</td>
          <td>🔥🔥🔥</td>
      </tr>
      <tr>
          <td>Snipaste</td>
          <td>Screenshot</td>
          <td>截图，置顶，</td>
          <td>🔥</td>
      </tr>
      <tr>
          <td>Xnip</td>
          <td>Screenshot</td>
          <td>滚动截图</td>
          <td>🔥</td>
      </tr>
      <tr>
          <td>raycast</td>
          <td>sys-Enhance</td>
          <td>替代原生的 Spotlight，插件支持，功能强大</td>
          <td>🔥🔥🔥</td>
      </tr>
      <tr>
          <td>Rectangle</td>
          <td>sys-Enhance</td>
          <td>窗口排列和贴靠</td>
          <td>🔥🔥🔥</td>
      </tr>
      <tr>
          <td>AltTab</td>
          <td>sys-Enhance</td>
          <td>支持 windows 的窗口切换，优化纯键盘体验</td>
          <td>🔥🔥</td>
      </tr>
      <tr>
          <td>KaraBiner</td>
          <td>external support</td>
          <td>外接键盘的控制和自定义和热键</td>
          <td>🔥🔥</td>
      </tr>
      <tr>
          <td>BetterDisplay</td>
          <td>external support</td>
          <td>外接显示器的全面控制</td>
          <td>🔥🔥</td>
      </tr>
      <tr>
          <td>MOS</td>
          <td>external support</td>
          <td>外接鼠标的 Smooth Scroll 支持</td>
          <td>🔥🔥</td>
      </tr>
      <tr>
          <td>Hidden bar</td>
          <td>beautify</td>
          <td>隐藏状态栏中不常用的 Icon</td>
          <td>🔥</td>
      </tr>
      <tr>
          <td>Top Notch</td>
          <td>beautify</td>
          <td>全黑隐藏刘海</td>
          <td>🔥</td>
      </tr>
      <tr>
          <td>CheatSheet</td>
          <td>Tips</td>
          <td>长按 Command 提示各个应用的快捷键</td>
          <td>🔥</td>
      </tr>
  </tbody>
</table>
<p>上面介绍的这些应用大多都是基于日常使用来介绍的，都是免费的软件，因此只要在 appstore 和官方网站进行下载即可，放心使用；</p>
<p>开发和办公需求的一些软件可能会涉及到部分配置，因此会单独介绍（其中像 office、微信 这些基本都会装的常见软件就不再额外介绍。）</p>
<h3 id="其他开发软件安装">其他开发软件安装</h3>
<table>
  <thead>
      <tr>
          <th>APP</th>
          <th>Type</th>
          <th>Desc</th>
          <th>Recommend</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>VsCode</td>
          <td>Editor(Code)</td>
          <td>∞</td>
          <td>💯</td>
      </tr>
      <tr>
          <td>Xcode</td>
          <td>Editor(Code)</td>
          <td>∞</td>
          <td>💯</td>
      </tr>
      <tr>
          <td>Obsidian</td>
          <td>Editor(Markdown)</td>
          <td>W(Md), R(PDF), Manager</td>
          <td>💯</td>
      </tr>
      <tr>
          <td>Typora</td>
          <td>Editor(Markdown)</td>
          <td>Single Markdown File</td>
          <td>😀</td>
      </tr>
      <tr>
          <td>iterm 2</td>
          <td>Terminal Simulator</td>
          <td>Best One in Mac</td>
          <td>💯</td>
      </tr>
      <tr>
          <td>HomeBrew</td>
          <td>CLI</td>
          <td>∞</td>
          <td>💯</td>
      </tr>
      <tr>
          <td>Beyond Compare</td>
          <td>Compare</td>
          <td>Not Free</td>
          <td>😀</td>
      </tr>
      <tr>
          <td>Office</td>
          <td>Office</td>
          <td>∞</td>
          <td>💯</td>
      </tr>
      <tr>
          <td>OneDrive</td>
          <td>Sync</td>
          <td>∞</td>
          <td>💯</td>
      </tr>
  </tbody>
</table>
<h3 id="开发环境搭建">开发环境搭建</h3>
<table>
  <thead>
      <tr>
          <th>APPs</th>
          <th>Type</th>
          <th>Desc</th>
          <th>IMG</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>KeyCastr</td>
          <td>Video</td>
          <td>Show Keyboard Input</td>
          <td></td>
      </tr>
      <tr>
          <td>Cursor Pro</td>
          <td>Video</td>
          <td>Enhance and Hightlight Cursor</td>
          <td></td>
      </tr>
      <tr>
          <td>Sidenote</td>
          <td>Note</td>
          <td>(Pay)like stickynote by in one side</td>
          <td></td>
      </tr>
  </tbody>
</table>
<h3 id="键位映射">键位映射</h3>
<p>inspired by @devaslife : karabiner-elements &ndash;cask;</p>
<p>安装完成后，我们需要在系统里面启用一大堆安全和隐私权限后，就可以开始键盘映射，可以在其中的网站找到一些映射方案，并导入自己的机器中。</p>
<ul>
<li><input checked="" disabled="" type="checkbox"> 找个时间来统一整理键盘映射</li>
</ul>
<h3 id="代理设置">代理设置</h3>
<ul>
<li><input checked="" disabled="" type="checkbox"> 修改为取消代理和设置代理的 Bash 脚本，便于切换。</li>
</ul>
<p>首先介绍代理的安装，配置好了代理方便访问 github、homebrew 等，方便我们对环境进行配置和软件下载。</p>
<p>系统代理我们使用ClashX Pro（Clash的Mac版本）进行配置，starlink推广警告。</p>
<p>Terminal的代理配置，<code>vim ~/.zshrc</code> or <code>vim ~/.bashrc</code>，添加下面这段，端口7890为默认，可到clash客户端中查看</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">https_proxy</span><span class="o">=</span>http://127.0.0.1:7890
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">http_proxy</span><span class="o">=</span>http://127.0.0.1:7890
</span></span><span class="line"><span class="cl"><span class="c1"># export all_proxy=sock5://127.0.0.1:7890</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>添加完成后，使用<code>source ~/.zshrc</code> 激活修改即可；</p>
<p>有时候由于切换设置或者取消使用Clash，需要取消代理</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nb">unset</span> http_proxy
</span></span><span class="line"><span class="cl"><span class="nb">unset</span> https_proxy</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以简单的写一个代理设置的脚本来进行快速设置.</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="k">function</span> SetProxy<span class="o">(){</span>
</span></span><span class="line"><span class="cl">  <span class="nb">export</span> <span class="nv">http_proxy</span><span class="o">=</span>http://127.0.0.1:7890
</span></span><span class="line"><span class="cl">  <span class="nb">export</span> <span class="nv">https_proxy</span><span class="o">=</span>https://127.0.0.1:7890
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">function</span> unsetProxy<span class="o">(){</span>
</span></span><span class="line"><span class="cl">  <span class="nb">unset</span> http_proxy
</span></span><span class="line"><span class="cl">  <span class="nb">unset</span> https_proxy
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">proxyon</span><span class="o">=</span>SetProxy
</span></span><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">proxyoff</span><span class="o">=</span>unsetProxy</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script>]]></content:encoded>
    </item>
    <item>
      <title>Linux02 基础指令</title>
      <link>https://aikenh.cn/posts/linux2/</link>
      <pubDate>Sun, 04 Sep 2022 21:30:00 +0000</pubDate>
      <guid>https://aikenh.cn/posts/linux2/</guid>
      <description>basic linux operation</description>
      <content:encoded><![CDATA[<p>@Aiken 2022</p>
<p>If u want get detail params info go to: <a href="http://www.explainshell.com" target="_blank" rel="noopener">http://www.explainshell.com</a>
.</p>
<h2 id="tar-压缩命令">tar 压缩命令</h2>
<p>linux中主要使用tar来进行文件的打包和解压，如果需要处理zip文件需要额外的支持，在上一章节中已经提到了，该章节压缩文件部分主要介绍tar命令</p>
<p><strong>压缩文件（夹）</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">tar -zcvf <span class="o">{</span>final_name<span class="o">}</span>.tgz <span class="o">{</span>dir<span class="o">}</span> --exclude<span class="o">={</span>dir/sub_dire1<span class="o">}</span>
</span></span><span class="line"><span class="cl">tar -cvf ...</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>解压文件（夹）</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">tar -zxvf <span class="o">{</span>tarfile<span class="o">}</span>.tgz -C <span class="o">{</span>指定目录<span class="o">}</span>
</span></span><span class="line"><span class="cl">tar -xvf ...</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="批量解压tar">批量解压tar</h3>
<p>编写脚本批量解压tar文件到对应的文件夹中，这里主要的核心在于脚本的编写，而非tar的package</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># version 1 ez2understrand</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> i in <span class="sb">`</span>ls *.tar.gz<span class="sb">`</span>
</span></span><span class="line"><span class="cl"><span class="k">do</span>
</span></span><span class="line"><span class="cl">    mkdir /dir/<span class="si">${</span><span class="nv">i</span><span class="p">/.tar.gz//</span><span class="si">}</span>
</span></span><span class="line"><span class="cl">    tar zxvf <span class="nv">$i</span> -C /dir/<span class="si">${</span><span class="nv">i</span><span class="p">/.tar.gz//</span><span class="si">}</span>
</span></span><span class="line"><span class="cl"><span class="k">done</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>也可以使用第二种方法：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># version 2 try to use assignment method</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 可以发现基本的操作是一样的，就是对应的定义的地方</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 可以考虑一下是如何使用echo和cut以及对应的-d 和 -f1是什么意思</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> file in <span class="sb">`</span>ls *.tar<span class="sb">`</span>
</span></span><span class="line"><span class="cl"><span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="nv">todir</span><span class="o">=</span><span class="sb">`</span><span class="nb">echo</span> <span class="nv">$file</span> <span class="p">|</span> cut -d<span class="s2">&#34;.&#34;</span> -f1<span class="sb">`</span>
</span></span><span class="line"><span class="cl">    mkdir <span class="nv">$todir</span> <span class="o">&amp;&amp;</span> tar -xvf <span class="nv">$file</span> -C <span class="nv">$todir</span>
</span></span><span class="line"><span class="cl"><span class="k">done</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>参考资料：<a href="https://www.cnblogs.com/hhandbibi/p/7283862.html" target="_blank" rel="noopener">tar压缩解压缩命令详解</a>
</p>
<h2 id="文件操作">文件操作</h2>
<h3 id="cd-路径切换"><code>cd</code> 路径切换</h3>
<p><code>cd</code> means change directory 切换工作区路径，毋庸置疑是最常使用的指令，基础用法<code>cd {path}</code></p>
<p><strong>返回上次目录</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nb">cd</span> -
</span></span><span class="line"><span class="cl"><span class="c1"># - equal to $OLDPWD</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>推荐使用 <a href="https://github.com/rupa/z" target="_blank" rel="noopener">zjump</a>
 能通过z指令快速定位目录，其通过frecency来管理地址优先级，能通过地址的简写，或者最终文件夹的名字快速跳转和定位。</p>
<h3 id="touch-新建"><code>touch</code> 新建</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">touch <span class="o">{</span>filename<span class="o">}</span>
</span></span><span class="line"><span class="cl">mkdir <span class="o">{</span>foldername<span class="o">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="rm-删除"><code>rm</code> 删除</h3>
<p>删除文件夹的时候需要-r指定递归删除，最好结合-v看看自己到底删了什么</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">rm -<span class="o">{</span>option<span class="o">}</span> <span class="o">{</span>filename<span class="o">}</span>
</span></span><span class="line"><span class="cl">rm -<span class="o">{</span>option<span class="o">}</span>r <span class="o">{</span>foldername<span class="o">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><blockquote>
<p>&ldquo;rm -f&rdquo; 强行删除，忽略不存在的文件，不提示确认。(force)
&ldquo;rm -i&rdquo; 进行交互式删除，即删除时会提示确认。(interactive)
&ldquo;rm -r&rdquo; 将参数中列出的全部目录和子目录进行递归删除。(recursive)
&ldquo;rm -v&rdquo; 详细显示删除操作进行的步骤。(verbose)</p>
</blockquote>
<p>删除文件夹中的文件，但是不删除文件夹</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">rm -rf <span class="o">{</span>folder<span class="o">}</span>/*</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="mv-移动"><code>mv</code> 移动</h3>
<p>mv 主要承担了以下两个职责：重命名、移动</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">mv <span class="o">{</span>fileA<span class="o">}</span> <span class="o">{</span>nameB<span class="o">}</span>
</span></span><span class="line"><span class="cl">mv files dir/</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>实际上name就代表了在系统中的position，所以当nameB可为地址，可以在移动的同时重命名。</p>
<p>建议使用<code>-i</code>参数强制执行提示功能， 避免意外覆盖文件。</p>
<h3 id="cp-拷贝"><code>cp</code> 拷贝</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># using cp to copy file</span>
</span></span><span class="line"><span class="cl">cp dir1/filea dir2/filea.bak -i</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>使用cp -i 强制询问是否覆盖，避免不必要的版本损失</li>
<li>-R 递归复制目录</li>
</ul>
<h3 id="ln-软连接"><code>ln</code> 软连接</h3>
<p>Linux 软连接，类似windows系统中做快捷方式</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 在target地址建立一个名为linkname的软连接，链接到source_dir</span>
</span></span><span class="line"><span class="cl">ln -s source_dir/ target_dir/linkname</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>删除快捷方式只需要<code>rm</code>即可，切记！！不要-f -v -r。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">rm linkname <span class="c1"># 删除软连接(注意后面千万不能有/)</span>
</span></span><span class="line"><span class="cl">mv linknamea linknameb <span class="c1"># 同理换名也是一样的</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>切换软连接连接的对象</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">ln -snf <span class="o">{</span>new source<span class="o">}</span> <span class="o">{</span>linkname<span class="o">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="search-搜索命令">Search 搜索命令</h2>
<h3 id="filetype-文件类型查看"><code>FileType</code> 文件类型查看</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">file my_file</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以查看符号连接的源目录</p>
<h3 id="list-files-列出文件"><code>List</code> Files 列出文件</h3>
<p><code>ls</code>: list directory contents.</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ls -l -r -t -h -s</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li><code>-l</code>: use a long listing format</li>
<li><code>-s</code>: print the allocated size of each file, in blocks</li>
<li><code>-t</code>: sort by time(modify, newest first)</li>
<li><code>-h</code>: human-readable</li>
<li><code>-r</code>: reverse order</li>
<li><code>-a</code>: show all files include those hide</li>
</ul>
<p>If we want to find file by &ldquo;pattern&rdquo;, we donot need <code>grep</code> we can do like this:</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ls *.md
</span></span><span class="line"><span class="cl">ls *todo*</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>列出文件，也可以使用<code>tree dir/</code>列出文件夹的层级结构。</p>
<p><strong>查看某个文件夹下文件或者文件夹的个数</strong>：<a href="https://blog.csdn.net/niguang09/article/details/6445778" target="_blank" rel="noopener">参考资料</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ls <span class="o">[</span>dirname<span class="o">]</span> -l<span class="p">|</span> grep <span class="s2">&#34;^-&#34;</span> <span class="p">|</span> wc -l  <span class="c1"># 1.查看某文件夹下文件的个数</span>
</span></span><span class="line"><span class="cl">ls <span class="o">[</span>dirname<span class="o">]</span> -lR<span class="p">|</span> grep <span class="s2">&#34;^-&#34;</span><span class="p">|</span> wc -l  <span class="c1"># 2.包括子文件夹下的文件</span>
</span></span><span class="line"><span class="cl">ls <span class="o">[</span>dirname<span class="o">]</span> -l<span class="p">|</span> grep <span class="s2">&#34;^d&#34;</span> <span class="p">|</span> wc -l  <span class="c1"># 3.只查看文件夹 </span>
</span></span><span class="line"><span class="cl">ls <span class="o">[</span>dirname<span class="o">]</span> -lR<span class="p">|</span> grep <span class="s2">&#34;^d&#34;</span><span class="p">|</span> wc -l  <span class="c1"># 4. 包括子文件夹中的文件夹</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 通过管道查看</span>
</span></span><span class="line"><span class="cl">ll <span class="p">|</span> wc -l</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="find-files-文件查找"><code>Find</code> Files 文件查找</h3>
<p><code>find</code>: search for files in a directory hierarchy</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">find <span class="o">[</span>path...<span class="o">]</span> -name &lt;pattern&gt;
</span></span><span class="line"><span class="cl"><span class="c1"># find file in this path by pattern</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="grep-content-格式匹配"><code>Grep</code> Content 格式匹配</h3>
<p>Linux grep 命令用于查找文件里符合条件的字符串。</p>
<p>grep 指令用于查找内容包含指定的范本样式的文件，如果发现某文件的内容符合所指定的范本样式，预设 grep 指令会把含有范本样式的那一列显示出来。若不指定任何文件名称，或是所给予的文件名为 <strong>-</strong>，则 grep 指令会从标准输入设备读取数据。</p>
<p>通过grep在命令行中筛选输出显示，只显示grep指定的部分。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 只显示其中包括str的部分</span>
</span></span><span class="line"><span class="cl"> <span class="nb">command</span> <span class="p">|</span> grep <span class="s1">&#39;str&#39;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>直接使用Grep搜索文档中的字符数据，</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">grep <span class="o">[</span>option<span class="o">]</span> pattern <span class="o">[</span>file<span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 该命令会在输入或指定的文件中搜索包含匹配指定模式的支付的行。</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>Option:</p>
<blockquote>
<p>-v 反向搜索，搜索不匹配该模式的行
-n 显示所在的行的行号
-c 显示有多少匹配到了
-e 来指定多个匹配模式 <code>grep -e p1 -e p2file1</code>
-r 递归搜索
-i 忽略大小写
-I 忽略二进制文件
-w, word-regexp</p>
</blockquote>
<p><strong>&ldquo;或&rdquo;</strong> 搜索：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">grep -E <span class="s2">&#34;optionA | optionB&#34;</span> *</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="history-command-历史命令查询"><code>History</code> Command 历史命令查询</h3>
<p>HISTORY主要针对如何找到历史指令，如何重复执行某一行指令；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># show the history command idx</span>
</span></span><span class="line"><span class="cl"><span class="nb">history</span>
</span></span><span class="line"><span class="cl"> <span class="m">1262</span> btm
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># resume this command idx, it&#39;ll get command by the idx</span>
</span></span><span class="line"><span class="cl">!1262
</span></span><span class="line"><span class="cl"> btm</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>CTRL+r</strong> : Reverse Cmd Searching</p>
<p>命令行反向搜索模式，方便输入重复的指令和地址，其会根据当前的键入内容去匹配历史指令。</p>
<h2 id="check-系统状态查看">Check 系统状态查看</h2>
<h3 id="系统时间显示">系统时间显示</h3>
<p><code>date &quot;+format&quot;</code> 通过在＋号的后面指定 format 来约束输出时间的样式，具体格式可以<a href="https://www.runoob.com/linux/linux-comm-date.html" target="_blank" rel="noopener">参考网站</a>
</p>
<h3 id="网络状态">网络状态</h3>
<p>ifconfig 命令需要先安装 net-tools，直接使用 <code>sudo apt-get install net-tools</code> 安装</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ifconfig</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><code>netstat</code> 命令用于显示网络连接、路由表、接口状态等网络信息。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">netstat</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>-i 显示网卡列表信息
-r 显示路由表信息
-l 列出正在监听的服务
-a 所有连接中的socket</p>
<h3 id="系统磁盘占用">系统磁盘占用</h3>
<p><strong>查看文件夹和磁盘的空间占用</strong>：<a href="https://www.explainshell.com/explain/1/du" target="_blank" rel="noopener">explain_shell du</a>
</p>
<p><code>df</code> 命令可以显示目前所有文件系统的可用空间和使用情形</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 参数 -h 表示使用「Human-readable」的输出，也就是在档案系统大小使用 GB、MB 等易读的格式。</span>
</span></span><span class="line"><span class="cl"> df -h</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><code>du</code> 查询文件或者当前文件夹的磁盘使用</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 查询当前文件夹下面各个文件夹的大小：</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 将深度改成n应该可以改变递归到子文件夹下的深度</span>
</span></span><span class="line"><span class="cl">du -h --max-depth<span class="o">=</span><span class="m">1</span> *
</span></span><span class="line"><span class="cl"><span class="c1"># *代表的是当前文件目录</span>
</span></span><span class="line"><span class="cl">du -h --max-depth<span class="o">=</span><span class="m">1</span> <span class="o">[</span>path<span class="o">]</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>查看当前目录下文件和文件夹的大小（定位哪里占用空间最大）：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># 查看当前文件夹下所有文件夹的占用空间</span>
</span></span><span class="line"><span class="cl">du -sh *
</span></span><span class="line"><span class="cl"><span class="c1"># 对应的查看指定文件夹大小的方式为：</span>
</span></span><span class="line"><span class="cl">du -sh dir</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="系统内存占用">系统内存占用</h3>
<p><code>free</code> 命令用于显示当前系统中的内存使用信息，使用 <code>free -h</code> 即可查看。</p>
<h3 id="watch-监控"><code>Watch</code> 监控</h3>
<p>将watch加在前面可以监控一些信息的实时变化</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">watch ps -aux
</span></span><span class="line"><span class="cl">watch nvidia-smi</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="cat-filemorelessnl"><code>Cat</code> File（more、less、nl）</h3>
<p>cat是显示文本文件中所有数据的得力工具，但是文件的文本会在显示器上一晃而过，难以控制后面的操作。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">cat file1</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>-n 给所有的行加上行号</li>
<li>-b 给非空行加上行号</li>
<li>-T 不显示制表符</li>
</ul>
<p><strong>more</strong>会显示文本文件的内容，但是会在每页数据之后停下来，使用spc/enter翻页，q退出</p>
<p><strong>less</strong>来自 less is more，是 more 的升级版，可以实现文件的前后移动和高级搜索功能。</p>
<p><strong>nl</strong> 命令式再 linux 中用来计算文件的行号，其会计算出每一个非空行（可以控制是否忽视）的行号，加在改行的前面输出改行，参考：<a href="https://www.cnblogs.com/peida/archive/2012/11/01/2749048.html" target="_blank" rel="noopener">每天一个linux命令(11)：nl命令</a>
</p>
<h3 id="head-doctail"><code>Head</code> Doc（Tail）</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">tail -n <span class="m">2</span> log_file
</span></span><span class="line"><span class="cl">tail -2 log_file
</span></span><span class="line"><span class="cl"><span class="c1"># -n &lt;N&gt; 显示文件的后面N行</span>
</span></span><span class="line"><span class="cl">head -5 log_file</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>只显示命令行输出的前几条或者后面几条</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">history</span> <span class="p">|</span> head -i
</span></span><span class="line"><span class="cl">histo <span class="p">|</span> tail -i</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>实时查看正在写入的文件 -f</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">tail -f file_inprocess.log</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="ps-进程操作"><code>ps</code> 进程操作</h2>
<p>ps 的英文全称为：process，主要用来查看系统中的进程状态，参数的主要参考资料：<a href="https://www.explainshell.com/explain/1/ps" target="_blank" rel="noopener">explain ps</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">ps -aux <span class="p">|</span> grep <span class="o">{</span>content<span class="o">}</span>
</span></span><span class="line"><span class="cl"><span class="nb">kill</span> <span class="o">{</span>PID<span class="o">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li><code>-a</code> 显示所有进程（-e同上）</li>
<li><code>-N</code> 显示与指定参数不符的所有进程</li>
<li><code>-u</code> 显示用户即 其他详细信息</li>
<li><code>-x</code> 显示没有控制终端的进程</li>
</ul>
<h3 id="其他进程操作命令">其他进程操作命令</h3>
<ul>
<li><code>pstree</code> 命令则可以结合 <code>ps</code> 命令，可用树状图的形式显示进程之间的关系。</li>
<li><code>top</code> 命令用于动态地监视进程的活动以及系统的负载</li>
<li><code>pidof</code> 命令可以查看<strong>指定服务</strong>进程的 PID 号码</li>
<li><code>killall</code> 复杂的服务进程可能会有多个 pid 进程号，killall 可以批量的终结指令</li>
</ul>
<h2 id="sleep-暂停">Sleep 暂停</h2>
<p><code>sleep t</code>引入一段时间的暂停</p>
]]></content:encoded>
    </item>
    <item>
      <title>Python Unittest 单元测试的编写与执行</title>
      <link>https://aikenh.cn/posts/unittest/</link>
      <pubDate>Fri, 12 Aug 2022 20:37:00 +0000</pubDate>
      <guid>https://aikenh.cn/posts/unittest/</guid>
      <description>Create and Run Unittest for python in VsCode</description>
      <content:encoded><![CDATA[<p>该文章将介绍 Python 中的单元测试之 Unittest 模块，及其在 VsCode 中的集成和使用，主要参考的链接有以下的三个：</p>
<ol>
<li><a href="https://blog.csdn.net/sinat_38682860/article/details/102838668" target="_blank" rel="noopener">Unittest的基本用法</a>
、<a href="https://docs.python.org/zh-cn/3/library/unittest.html" target="_blank" rel="noopener">Python官方文档</a>
</li>
<li><a href="https://blog.csdn.net/CloserSide/article/details/109175775" target="_blank" rel="noopener">VsCode运行Unittest</a>
，其对应 VsCode 侧边栏中的“测试”模块，该部分就由本文来自行补充</li>
<li>使用Unittest<a href="https://blog.csdn.net/weixin_44520259/article/details/107840219" target="_blank" rel="noopener">模拟input的输入</a>
，便于测试基于命令行输入的代码</li>
</ol>
<h2 id="基本用法">基本用法</h2>
<p>在工作区中定义示例函数如下，基于该函数进行Unittest的测试和演示：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># we save this function in function_module.py</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">add_4_ut</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">a</span><span class="o">+</span><span class="n">b</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>基本使用的代码如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">unittest</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">function_module</span> <span class="kn">import</span> <span class="n">add_4_ut</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 使用TestCase基类构建测试样例和测试方法，运行的时候会对编写的所有测试方法进行测试</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">TestAddFunction</span><span class="p">(</span><span class="n">unittest</span><span class="o">.</span><span class="n">TestCase</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">test_ez</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">add_4_ut</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">5</span><span class="p">),</span><span class="mi">8</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">test_complex</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="k">assert</span><span class="p">(</span><span class="n">add_4_ut</span><span class="p">(</span><span class="mi">1023</span><span class="p">,</span><span class="mi">2032</span><span class="p">),</span><span class="mi">3055</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="o">...</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># using the main function buildin the unittest, to run all the method we define in the TestCale.</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">unittest</span><span class="o">.</span><span class="n">main</span><span class="p">()</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="模拟命令行输入">模拟命令行输入</h3>
<p>使用unittest.mock的patch模块进行输入输出模块的模拟和测试，具体的使用方法如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">unittest</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">unittest.mock</span> <span class="kn">import</span> <span class="n">patch</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">function_count</span> <span class="kn">import</span> <span class="n">entry_point</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 使用TestCase基类构建测试样例和测试方法，运行的时候会对编写的所有测试方法进行测试</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">TestAddFunction</span><span class="p">(</span><span class="n">unittest</span><span class="o">.</span><span class="n">TestCase</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1"># 使用patch模块来替换默认模块中的input方法</span>
</span></span><span class="line"><span class="cl">    <span class="nd">@patch</span><span class="p">(</span><span class="s1">&#39;builtins.input&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">test_ez</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">mock_input</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 利用return_value来模拟输入模块的输入</span>
</span></span><span class="line"><span class="cl">        <span class="n">mock_input</span><span class="o">.</span><span class="n">return_value</span> <span class="o">=</span> <span class="s2">&#34;1,2,3,4&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">entry_point</span><span class="p">(),</span> <span class="mi">24</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="vscode运行unittest">VsCode运行Unittest</h2>
<p>VsCode配置了python的测试框架，更好的支持测试进程的进行，通过以下的方式进行相应的设置：</p>
<ul>
<li>
<p>首先使用<code>ctrl</code>+<code>shift</code>+<code>p</code>调出命令行界面，输入<code>python configure test</code>，选择<code>unittest</code>，并选择放置<code>test_xxx.py</code>地址，以及测试文件的命名规则例如<code>test_&lt;name&gt;.py</code>的即可</p>
</li>
<li>
<p>在对应路径下编写对应的测试文件，可以在测试文件中出现，快捷测试的按钮，以及测试后的结果：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220813230817445.png">
    <img alt="image-20220813230817445" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220813230817445.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220813230817445.png" style="display: block; margin: 0 auto;"
      alt="image-20220813230817445"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
</li>
<li>
<p>左侧的测试菜单也会显示当前路径下的所有测试方法，可以按照自己想要的方式进行测试。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220813230902633.png">
    <img alt="image-20220813230902633" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220813230902633.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220813230902633.png" style="display: block; margin: 0 auto;"
      alt="image-20220813230902633"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>SQL Chapter5 mysql与事务</title>
      <link>https://aikenh.cn/posts/sql5/</link>
      <pubDate>Fri, 05 Aug 2022 17:30:00 +0000</pubDate>
      <guid>https://aikenh.cn/posts/sql5/</guid>
      <description>mySQL and business</description>
      <content:encoded><![CDATA[<p>廖雪峰的SQL教程的学习笔记</p>
<h2 id="mysql">mySQL</h2>
<p>how to connect mysql? Using CMD(or MySQL Client) to carry out</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># local, default port is 3306</span>
</span></span><span class="line"><span class="cl">mysql -u root -p
</span></span><span class="line"><span class="cl"><span class="c1"># remote</span>
</span></span><span class="line"><span class="cl">mysql -h &lt;ip&gt; -u root -p</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>root here is the <code>&lt;username&gt;</code>, we may using other name in specific situation.</p>
<p><code>mysql</code>实际上时MySQL的客户端，真正的MySQL服务器程序时<code>mysqld</code>在后台运行。</p>
<hr>
<p>如果希望借助可视化图形界面进行操作，可以使用<a href="https://dev.mysql.com/downloads/workbench/" target="_blank" rel="noopener">MySQL Workbench</a>
进行可视化的增删改查（底层还是基于sql的命令行指令进行）。</p>
<h3 id="数据库">数据库</h3>
<p>运行MySQL的服务器可以同时创建多个数据库</p>
<ul>
<li>可以使用<code>SHOW DATABASES;</code>列出所有的数据库，其中<code>information_schema</code>、<code>mysql</code>、<code>performance_schema</code>和<code>sys</code>是系统库，不要去改动它们。其他的是用户创建的数据库。</li>
<li>新建数据库：<code>CREATE DATABASE &lt;database_name&gt;;</code></li>
<li>删除数据库：<code>DROP DATABASE;</code>其中的数据将被完全删除</li>
<li>进入数据库（切换活动的数据库）:<code>USE &lt;database_name&gt;;</code>当我们切换到指定数据库的时候，我们才能对其进行操作</li>
</ul>
<h3 id="表">表</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- 列出所有表
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SHOW</span><span class="w"> </span><span class="n">TABLES</span><span class="err">；</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">-- 查看表的结构
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">DESC</span><span class="w"> </span><span class="o">&lt;</span><span class="n">tables_name</span><span class="o">&gt;</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">-- 查看创建表的语句
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SHOW</span><span class="w"> </span><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="o">&lt;</span><span class="n">tables_name</span><span class="o">&gt;</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">-- 创建表
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="o">&lt;</span><span class="n">tables_name</span><span class="o">&gt;</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">-- 删除表
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">DROP</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="o">&lt;</span><span class="n">tables_name</span><span class="o">&gt;</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果要修改表的话，相对更为复杂一些，如果要为表增加一列<code>birth</code>,使用</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">ALTER</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="k">ADD</span><span class="w"> </span><span class="k">COLUMN</span><span class="w"> </span><span class="n">birth</span><span class="w"> </span><span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>名称后面指定类型和是否允许为NULL。</p>
<p>修改特定列的名称和属性的话：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">ALTER</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="n">CHANGE</span><span class="w"> </span><span class="k">COLUMN</span><span class="w"> </span><span class="n">birth</span><span class="w"> </span><span class="n">birthday</span><span class="w"> </span><span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">20</span><span class="p">)</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>删除列使用：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">ALTER</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="k">DROP</span><span class="w"> </span><span class="k">COLUMN</span><span class="w"> </span><span class="n">birthday</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="实用sql语句">实用SQL语句</h2>
<h3 id="插入或替换">插入或替换</h3>
<p>如果我们希望插入一条新记录（INSERT），但如果记录已经存在，就先删除原记录，再插入新记录。此时，可以使用<code>REPLACE</code>语句，这样就不必先查询，再决定是否先删除再插入：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">REPLACE</span><span class="w"> </span><span class="k">INTO</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="p">(</span><span class="n">id</span><span class="p">,</span><span class="w"> </span><span class="n">class_id</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">gender</span><span class="p">,</span><span class="w"> </span><span class="n">score</span><span class="p">)</span><span class="w"> </span><span class="k">VALUES</span><span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;小明&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;F&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">99</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>若<code>id=1</code>的记录不存在，<code>REPLACE</code>语句将插入新记录，否则，当前<code>id=1</code>的记录将被删除，然后再插入新记录。</p>
<h3 id="插入或更新">插入或更新</h3>
<p>如果我们希望插入一条新记录（INSERT），但如果记录已经存在，就更新该记录，此时，可以使用<code>INSERT INTO ... ON DUPLICATE KEY UPDATE ...</code>语句：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">INSERT</span><span class="w"> </span><span class="k">INTO</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="p">(</span><span class="n">id</span><span class="p">,</span><span class="w"> </span><span class="n">class_id</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">gender</span><span class="p">,</span><span class="w"> </span><span class="n">score</span><span class="p">)</span><span class="w"> </span><span class="k">VALUES</span><span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;小明&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;F&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">99</span><span class="p">)</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="n">DUPLICATE</span><span class="w"> </span><span class="k">KEY</span><span class="w"> </span><span class="k">UPDATE</span><span class="w"> </span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;小明&#39;</span><span class="p">,</span><span class="w"> </span><span class="n">gender</span><span class="o">=</span><span class="s1">&#39;F&#39;</span><span class="p">,</span><span class="w"> </span><span class="n">score</span><span class="o">=</span><span class="mi">99</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>若<code>id=1</code>的记录不存在，<code>INSERT</code>语句将插入新记录，否则，当前<code>id=1</code>的记录将被更新，更新的字段由<code>UPDATE</code>指定。</p>
<h3 id="插入或忽略">插入或忽略</h3>
<p>如果我们希望插入一条新记录（INSERT），但如果记录已经存在，就啥事也不干直接忽略，此时，可以使用<code>INSERT IGNORE INTO ...</code>语句：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">INSERT</span><span class="w"> </span><span class="k">IGNORE</span><span class="w"> </span><span class="k">INTO</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="p">(</span><span class="n">id</span><span class="p">,</span><span class="w"> </span><span class="n">class_id</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">gender</span><span class="p">,</span><span class="w"> </span><span class="n">score</span><span class="p">)</span><span class="w"> </span><span class="k">VALUES</span><span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;小明&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;F&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">99</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>若<code>id=1</code>的记录不存在，<code>INSERT</code>语句将插入新记录，否则，不执行任何操作。</p>
<h3 id="快照">快照</h3>
<p>如果想要对一个表进行快照，即复制一份当前表的数据到一个新表，可以结合<code>CREATE TABLE</code>和<code>SELECT</code>：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- 对class_id=1的记录进行快照，并存储为新表students_of_class1:
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">students_of_class1</span><span class="w"> </span><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">class_id</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>新创建的表结构和<code>SELECT</code>使用的表结构完全一致。</p>
<h3 id="写入查询结果集">写入查询结果集</h3>
<p>如果查询结果集需要写入到表中，可以结合<code>INSERT</code>和<code>SELECT</code>，将<code>SELECT</code>语句的结果集直接插入到指定表中。</p>
<p>例如，创建一个统计成绩的表<code>statistics</code>，记录各班的平均成绩：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">CREATE</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="k">statistics</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">id</span><span class="w"> </span><span class="nb">BIGINT</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="w"> </span><span class="n">AUTO_INCREMENT</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">class_id</span><span class="w"> </span><span class="nb">BIGINT</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">average</span><span class="w"> </span><span class="n">DOUBLE</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">PRIMARY</span><span class="w"> </span><span class="k">KEY</span><span class="w"> </span><span class="p">(</span><span class="n">id</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>然后，我们就可以用一条语句写入各班的平均成绩：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">INSERT</span><span class="w"> </span><span class="k">INTO</span><span class="w"> </span><span class="k">statistics</span><span class="w"> </span><span class="p">(</span><span class="n">class_id</span><span class="p">,</span><span class="w"> </span><span class="n">average</span><span class="p">)</span><span class="w"> </span><span class="k">SELECT</span><span class="w"> </span><span class="n">class_id</span><span class="p">,</span><span class="w"> </span><span class="k">AVG</span><span class="p">(</span><span class="n">score</span><span class="p">)</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="k">GROUP</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">class_id</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>确保<code>INSERT</code>语句的列和<code>SELECT</code>语句的列能一一对应，就可以在<code>statistics</code>表中直接保存查询的结果：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="o">&gt;</span><span class="w"> </span><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="k">statistics</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="o">+</span><span class="c1">----+----------+--------------+
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="o">|</span><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">class_id</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">average</span><span class="w">      </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="o">+</span><span class="c1">----+----------+--------------+
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="o">|</span><span class="w">  </span><span class="mi">1</span><span class="w"> </span><span class="o">|</span><span class="w">        </span><span class="mi">1</span><span class="w"> </span><span class="o">|</span><span class="w">         </span><span class="mi">86</span><span class="p">.</span><span class="mi">5</span><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="o">|</span><span class="w">  </span><span class="mi">2</span><span class="w"> </span><span class="o">|</span><span class="w">        </span><span class="mi">2</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="mi">73</span><span class="p">.</span><span class="mi">666666666</span><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="o">|</span><span class="w">  </span><span class="mi">3</span><span class="w"> </span><span class="o">|</span><span class="w">        </span><span class="mi">3</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="mi">88</span><span class="p">.</span><span class="mi">333333333</span><span class="w"> </span><span class="o">|</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="o">+</span><span class="c1">----+----------+--------------+
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="mi">3</span><span class="w"> </span><span class="k">rows</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="k">set</span><span class="w"> </span><span class="p">(</span><span class="mi">0</span><span class="p">.</span><span class="mi">00</span><span class="w"> </span><span class="n">sec</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="强制使用指定索引">强制使用指定索引</h3>
<p>在查询的时候，数据库系统会自动分析查询语句，并选择一个最合适的索引。但是很多时候，数据库系统的查询优化器并不一定总是能使用最优索引。如果我们知道如何选择索引，可以使用<code>FORCE INDEX</code>强制查询使用指定的索引。例如：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="o">&gt;</span><span class="w"> </span><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="k">FORCE</span><span class="w"> </span><span class="k">INDEX</span><span class="w"> </span><span class="p">(</span><span class="n">idx_class_id</span><span class="p">)</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">class_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="k">DESC</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>指定索引的前提是索引<code>idx_class_id</code>必须存在。</p>
<h2 id="事务">事务</h2>
<p>在执行SQL语句的时候，某些业务要求，一系列操作必须全部执行，而不能仅执行一部分。例如，一个转账操作：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span></span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code>-- 从id=1的账户给id=2的账户转账100元
-- 第一步：将id=1的A账户余额减去100
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
-- 第二步：将id=2的B账户余额加上100
UPDATE accounts SET balance = balance + 100 WHERE id = 2;</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这两条SQL语句必须全部执行，或者，由于某些原因，如果第一条语句成功，第二条语句失败，就必须全部撤销。</p>
<p>这种把多条语句作为一个整体进行操作的功能，被称为数据库<em>事务</em>。数据库事务可以确保该事务范围内的所有操作都可以全部成功或者全部失败。如果事务失败，那么效果就和没有执行这些SQL一样，不会对数据库数据有任何改动。</p>
<p><strong>可见，数据库事务需要具有ACID四个特性</strong></p>
<ul>
<li>A：Atomic，原子性，将所有SQL作为原子工作单元执行，要么全部执行，要么全部不执行；</li>
<li>C：Consistent，一致性，事务完成后，所有数据的状态都是一致的，即A账户只要减去了100，B账户则必定加上了100；</li>
<li>I：Isolation，隔离性，如果有多个事务并发执行，每个事务作出的修改必须与其他事务隔离；</li>
<li>D：Duration，持久性，即事务完成后，对数据库数据的修改被持久化存储。</li>
</ul>
<p>对于单条SQL语句，数据库系统自动将其作为一个事务执行，这种事务被称为<em><strong>隐式事务</strong></em>。</p>
<p>要手动把多条SQL语句作为一个事务执行，使用<code>BEGIN</code>开启一个事务，使用<code>COMMIT</code>提交一个事务，这种事务被称为<em>显式事务</em>，例如，把上述的转账操作作为一个显式事务：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">BEGIN</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">UPDATE</span><span class="w"> </span><span class="n">accounts</span><span class="w"> </span><span class="k">SET</span><span class="w"> </span><span class="n">balance</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">balance</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">100</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">UPDATE</span><span class="w"> </span><span class="n">accounts</span><span class="w"> </span><span class="k">SET</span><span class="w"> </span><span class="n">balance</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">balance</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">100</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">2</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">COMMIT</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><code>COMMIT</code>是指提交事务，即试图把事务内的所有SQL所做的修改永久保存。如果<code>COMMIT</code>语句执行失败了，整个事务也会失败。</p>
<p>有些时候，我们希望主动让事务失败，这时，可以用<code>ROLLBACK</code>回滚事务，整个事务会失败：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">BEGIN</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">UPDATE</span><span class="w"> </span><span class="n">accounts</span><span class="w"> </span><span class="k">SET</span><span class="w"> </span><span class="n">balance</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">balance</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">100</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">UPDATE</span><span class="w"> </span><span class="n">accounts</span><span class="w"> </span><span class="k">SET</span><span class="w"> </span><span class="n">balance</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">balance</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">100</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">2</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">ROLLBACK</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>对于两个并发执行的事务，如果涉及到操作同一条记录的时候，可能会发生问题。因为并发操作会带来数据的不一致性，包括脏读、不可重复读、幻读等。数据库系统提供了隔离级别来让我们有针对性地选择事务的隔离级别，避免数据不一致的问题。</p>
<p>SQL标准定义了4种隔离级别，分别对应可能出现的数据不一致的情况：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: left">Isolation Level</th>
          <th style="text-align: left">脏读（Dirty Read）</th>
          <th style="text-align: left">不可重复读（Non Repeatable Read）</th>
          <th style="text-align: left">幻读（Phantom Read）</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: left">Read Uncommitted</td>
          <td style="text-align: left">Yes</td>
          <td style="text-align: left">Yes</td>
          <td style="text-align: left">Yes</td>
      </tr>
      <tr>
          <td style="text-align: left">Read Committed</td>
          <td style="text-align: left">-</td>
          <td style="text-align: left">Yes</td>
          <td style="text-align: left">Yes</td>
      </tr>
      <tr>
          <td style="text-align: left">Repeatable Read</td>
          <td style="text-align: left">-</td>
          <td style="text-align: left">-</td>
          <td style="text-align: left">Yes</td>
      </tr>
      <tr>
          <td style="text-align: left">Serializable</td>
          <td style="text-align: left">-</td>
          <td style="text-align: left">-</td>
          <td style="text-align: left">-</td>
      </tr>
  </tbody>
</table>
<p>我们会依次介绍4种隔离级别的数据一致性问题。</p>
<ul>
<li>在这种隔离级别下，一个事务会读到另一个事务更新后但未提交的数据，如果另一个事务回滚，那么当前事务读到的数据就是脏数据，这就是脏读（Dirty Read）。</li>
<li>在Read Committed隔离级别下，一个事务可能会遇到不可重复读（Non Repeatable Read）的问题。不可重复读是指，在一个事务内，多次读同一数据，在这个事务还没有结束时，如果另一个事务恰好修改了这个数据，那么，在第一个事务中，两次读取的数据就可能不一致。</li>
<li>在Repeatable Read隔离级别下，一个事务可能会遇到幻读（Phantom Read）的问题，幻读是指，在一个事务中，第一次查询某条记录，发现没有，但是，当试图更新这条不存在的记录时，竟然能成功，并且，再次读取同一条记录，它就神奇地出现了。</li>
</ul>
<p>Serializable是最严格的隔离级别。在Serializable隔离级别下，所有事务按照次序依次执行，因此，脏读、不可重复读、幻读都不会出现。</p>
<p>虽然Serializable隔离级别下的事务具有最高的安全性，但是，由于事务是串行执行，所以效率会大大下降，应用程序的性能会急剧降低。如果没有特别重要的情景，一般都不会使用Serializable隔离级别。</p>
<h3 id="默认隔离级别">默认隔离级别</h3>
<p>如果没有指定隔离级别，数据库就会使用默认的隔离级别。在MySQL中，如果使用InnoDB，默认的隔离级别是Repeatable Read。</p>
]]></content:encoded>
    </item>
    <item>
      <title>SQL Chapter4  增删改相关操作</title>
      <link>https://aikenh.cn/posts/sql4/</link>
      <pubDate>Fri, 05 Aug 2022 15:20:00 +0000</pubDate>
      <guid>https://aikenh.cn/posts/sql4/</guid>
      <description>增删改（查）</description>
      <content:encoded><![CDATA[<p>基本操作无非就是增删改查，查询在上一章Select已经学习完毕，而剩下的增、删、改对应的关键词分别是：</p>
<ul>
<li>INSERT：插入新纪录</li>
<li>UPDATE：更新现有记录</li>
<li>DELETE：删除已有记录</li>
</ul>
<p>接下来具体讨论各种用法：</p>
<h2 id="插入">插入</h2>
<p>使用关键字<code>INSERT</code>进行数据和记录的插入，其基本语法如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>SQL</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-SQL" data-lang="SQL"><span class="line"><span class="cl"><span class="k">INSERT</span><span class="w"> </span><span class="k">INTO</span><span class="w"> </span><span class="o">&lt;</span><span class="err">表名</span><span class="o">&gt;</span><span class="p">(</span><span class="err">字段</span><span class="mi">1</span><span class="p">,</span><span class="err">字段</span><span class="mi">2</span><span class="p">,...)</span><span class="w"> </span><span class="k">VALUES</span><span class="p">(</span><span class="err">值</span><span class="mi">1</span><span class="err">，值</span><span class="mi">2</span><span class="p">,...)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>例如向<code>students</code>表中插入一条新数据，先列出需要添加数据的字段，然后按照字段的次序添加值</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- 添加记录
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">INSERT</span><span class="w"> </span><span class="k">INTO</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="p">(</span><span class="n">class_id</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">gender</span><span class="p">,</span><span class="w"> </span><span class="n">score</span><span class="p">)</span><span class="w"> </span><span class="n">value</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="s1">&#39;大牛&#39;</span><span class="p">,</span><span class="s1">&#39;M&#39;</span><span class="p">,</span><span class="mi">80</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>自增字段（id）或者其他有默认值的字段可以省略。其中需要注意的是：</p>
<ul>
<li>字段顺序不必和数据库表的字段顺序一致</li>
<li>但是值的顺序必须和字段顺序一致</li>
</ul>
<p>同时<strong>插入多条记录</strong>的写法如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">INSERT</span><span class="w"> </span><span class="k">INTO</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="p">(</span><span class="n">class_id</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">gender</span><span class="p">,</span><span class="w"> </span><span class="n">score</span><span class="p">)</span><span class="w"> </span><span class="k">VALUES</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;大宝&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;M&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">87</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;二宝&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;M&#39;</span><span class="p">,</span><span class="w"> </span><span class="mi">81</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="更新">更新</h2>
<p>使用关键字<code>update</code>更新数据表中的记录，其基本语法如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">UPDATE</span><span class="w"> </span><span class="o">&lt;</span><span class="err">表名</span><span class="o">&gt;</span><span class="w"> </span><span class="k">SET</span><span class="w"> </span><span class="err">字段</span><span class="mi">1</span><span class="o">=</span><span class="err">值</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="err">字段</span><span class="mi">2</span><span class="o">=</span><span class="err">值</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="p">...;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>前面填写修改后的值，通过<code>WHERE</code>选出我们需要修改的记录</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">UPDATE</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="k">SET</span><span class="w"> </span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;大牛&#39;</span><span class="p">,</span><span class="w"> </span><span class="n">score</span><span class="o">=</span><span class="mi">66</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">id</span><span class="o">=</span><span class="mi">2</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>由于基于条件记录的特性，我们可以<strong>一次</strong>修改条件筛选出来的<strong>多个记录</strong>，同时可以在更新过程中使用表达式，</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">UPDATE</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="k">SET</span><span class="w"> </span><span class="n">score</span><span class="o">=</span><span class="n">score</span><span class="o">+</span><span class="mi">10</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">score</span><span class="o">&lt;</span><span class="mi">80</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>上式会将所有80分以下的同学的分数＋10分</p>
<p>当没有使用WHERE的时候将会对表的整体进行更新，需要谨慎使用。</p>
<blockquote>
<p>在使用真实的MySQL这类关系数据库时，update会返回更新的行数以及WHERE条件匹配的行数。</p>
</blockquote>
<h2 id="删除">删除</h2>
<p>删除显然使用的时<code>DELETE</code>语句，其基本语法如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">DELETE</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="o">&lt;</span><span class="err">表名</span><span class="o">&gt;</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="p">...;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>例如：删除students表中id=1的记录</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">DELETE</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">id</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>和更新类似，基于条件也可能一次删除多个记录，如果没有匹配就没有删除，不带条件的删除将会删除整个表格。</p>
<blockquote>
<p>在使用真实的MySQL这类关系数据库时，delete会返回删除的行数以及WHERE条件匹配的行数。</p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>SQL Chapter3 查询命令</title>
      <link>https://aikenh.cn/posts/sql3/</link>
      <pubDate>Thu, 04 Aug 2022 14:40:00 +0000</pubDate>
      <guid>https://aikenh.cn/posts/sql3/</guid>
      <description>Query in SQL</description>
      <content:encoded><![CDATA[<p>该章节介绍SQL中的查询命令，根据<a href="https://www.liaoxuefeng.com/wiki/1177760294764384/1179610888796448" target="_blank" rel="noopener">廖雪峰网站</a>
进行一步步的测试和学习即可。</p>
<ul>
<li>其中<code>–</code>为sql语言中的注释符号。</li>
<li>关键词不区分大小写</li>
</ul>
<h2 id="基本查询">基本查询</h2>
<p>查询表中的所有数据主要使用关键词<code>SELECT</code></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="o">&lt;</span><span class="err">表名</span><span class="o">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li><code>SELECT</code>表明要执行查询</li>
<li><code>*</code>代表“所有列”</li>
<li><code>FROM</code>表明要从哪个表查询</li>
</ul>
<p>当指定特定列名的时候（也就是所谓的<strong>投影查询</strong>）格式如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="o">&lt;</span><span class="n">KEY1</span><span class="o">&gt;</span><span class="p">,</span><span class="o">&lt;</span><span class="n">KEY2</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="o">&lt;</span><span class="err">表名</span><span class="o">&gt;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">-- 注释</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>此外，许多工具会使用<code>SELECT 1;</code>来测试数据库链接的有效性；<code>SELECT 100+200</code>也可以用来做简单的计算。</p>
<h2 id="条件查询">条件查询</h2>
<p><strong>条件查询详细资料</strong>：<a href="https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_between" target="_blank" rel="noopener">sql</a>
，通过官方网站可以找到更完整的条件语句和用法</p>
<p>在<code>SELECT</code>命令中添加<code>WHERE</code>关键词进行条件查询</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="o">&lt;</span><span class="err">表名</span><span class="o">&gt;</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="o">&lt;</span><span class="err">条件表达式</span><span class="o">&gt;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">-- 一个典型的例子如下
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">score</span><span class="o">&gt;</span><span class="mi">80</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">gender</span><span class="o">=</span><span class="s1">&#39;M&#39;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在sql中主要的条件语句关键字为：<code>AND</code>，<code>OR</code>，<code>NOT</code></p>
<p>可以使用<code>()</code>来组合条件语句（3个或或者更多条件常用）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="p">(</span><span class="n">score</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="mi">80</span><span class="w"> </span><span class="k">OR</span><span class="w"> </span><span class="n">score</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="mi">90</span><span class="p">)</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">gender</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;M&#39;</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果不使用括号组合的话，就按照传统的条件语句的优先级来执行即<code>NOT</code>，<code>AND</code>，<code>OR</code></p>
<p>还有一些其他的规则如下</p>
<table>
  <thead>
      <tr>
          <th>条件</th>
          <th>表达式举例1</th>
          <th>表达式举例2</th>
          <th>说明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>=</td>
          <td>score=80</td>
          <td>name=’abc‘</td>
          <td>字符串需要用单引号括起来</td>
      </tr>
      <tr>
          <td>&lt;&gt;判断不相等</td>
          <td>score&lt;&gt;80</td>
          <td>name&lt;&gt;‘abc’</td>
          <td></td>
      </tr>
      <tr>
          <td>使用LIKE判断相似</td>
          <td>name LIKE ’ab%‘</td>
          <td>name like ’%ab%</td>
          <td>%表示任意数量的任意字符</td>
      </tr>
  </tbody>
</table>
<h2 id="基于排序显示结果">基于排序显示结果</h2>
<p>使用<code>SELECT</code>查询时，结果通常按照<code>id</code>进行排序，也就是按照主键进行排序，这也是默认的做法，如果我们希望结果按照某些特定的条件来排序可以使用：<code>ORDER BY</code>语句。</p>
<p>例如我们希望按照成绩从低到高显示结果：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">id</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">gender</span><span class="p">,</span><span class="w"> </span><span class="n">score</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">score</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>从高到低的话则加入<code>DESC</code>关键词来使用倒序的输出，（默认的升序ASC可以省略）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">id</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">gender</span><span class="p">,</span><span class="w"> </span><span class="n">score</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">score</span><span class="w"> </span><span class="k">DESC</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>考虑到单项排序可能出现值相同的情况，可以加入第二关键词，当score相同的时候就用gender排序</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">id</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">gender</span><span class="p">,</span><span class="w"> </span><span class="n">score</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">score</span><span class="w"> </span><span class="k">DESC</span><span class="p">,</span><span class="w"> </span><span class="n">gender</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果在基于排序的情况下还要使用条件语句的话，需要将<code>WHERE</code>子句放在<code>ORDER BY</code>子句前面。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">id</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">gender</span><span class="p">,</span><span class="w"> </span><span class="n">score</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">students</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">WHERE</span><span class="w"> </span><span class="n">class_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">score</span><span class="w"> </span><span class="k">DESC</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="分页查询">分页查询</h2>
<p>使用<code>SELECT</code>查询时，如果结果数据量很大，一页显示的话数据量太大，我们最好分页显示，实现的代码如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">id</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">gender</span><span class="p">,</span><span class="w"> </span><span class="n">score</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">students</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">score</span><span class="w"> </span><span class="k">DESC</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">LIMIT</span><span class="w"> </span><span class="mi">100</span><span class="w"> </span><span class="k">OFFSET</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><code>LIMIT</code>表示最多取几条，<code>OFFSET</code>表示从第几条开始，第二页就是`LIMIT 100, OFFSET 100.</p>
<ul>
<li><code>LIMIT</code>总是设定为<code>pageSize</code></li>
<li><code>OFFSET</code>计算公式为<code>pageSize * (pageIndex-1)</code></li>
</ul>
<p>如果<code>OFFSET</code>超过了最大的数量，会得到空的结果集，该命令可以简写为</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">LIMIT</span><span class="w"> </span><span class="mi">100</span><span class="p">,</span><span class="mi">100</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="聚合查询">聚合查询</h2>
<p>SQL提供了聚合函数来针对查询结果进一步的统计分析，使用聚合函数进行查询就是聚合查询，它可以快速的获得结果。</p>
<p>比如计数，通过聚合函数就不需要一个个去数了</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="k">COUNT</span><span class="p">(</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">students</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><code>COUNT(*)</code>表示查询所有列的行数，要注意聚合的计算结果虽然是一个数字，但查询的结果仍然是一个二维表，只是这个二维表只有一行一列，并且列名是<code>COUNT(*)</code>，因此我们应该给该参数设置一个名字（变量名）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="k">COUNT</span><span class="p">(</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="n">num</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">students</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这样列名就是num了。</p>
<p>此外聚合查询，支持<code>WHERE</code>等语句，还有其他的聚合函数如下（更多可以上官网等去查询）：</p>
<table>
  <thead>
      <tr>
          <th>函数</th>
          <th>说明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>SUM</td>
          <td>合计值，必须为数值类型</td>
      </tr>
      <tr>
          <td>AVG</td>
          <td>平均值，必须为数值类型</td>
      </tr>
      <tr>
          <td>MAX</td>
          <td>计算某一列的最大值，字符类型会返回排序最后的</td>
      </tr>
      <tr>
          <td>MIN</td>
          <td>计算某一列的最大值，字符类型会返回排序最前的</td>
      </tr>
  </tbody>
</table>
<p>要特别注意：如果聚合查询的<code>WHERE</code>条件没有匹配到任何行，<code>COUNT()</code>会返回0，而<code>SUM()</code>、<code>AVG()</code>、<code>MAX()</code>和<code>MIN()</code>会返回<code>NULL</code>：</p>
<h3 id="分组聚合">分组聚合</h3>
<p>如果我们要统计一班的学生数量，我们知道，可以用<code>SELECT COUNT(*) num FROM students WHERE class_id = 1;</code>。如果要继续统计二班、三班的学生数量，难道必须不断修改<code>WHERE</code>条件来执行<code>SELECT</code>语句吗？</p>
<p>对于聚合查询，SQL还提供了“分组聚合”的功能。我们使用下列的聚合查询方法：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="k">COUNT</span><span class="p">(</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="n">num</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="k">GROUP</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">class_id</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>实现值和变量的相互对应，我们可以将二维表每行的名称加上：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">class_id</span><span class="p">,</span><span class="w"> </span><span class="k">COUNT</span><span class="p">(</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="n">num</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="k">GROUP</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">class_id</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>更进一步的，如果我们希望得到每个班的男女人数可以使用：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">class_id</span><span class="p">,</span><span class="w"> </span><span class="n">gender</span><span class="p">,</span><span class="w"> </span><span class="k">COUNT</span><span class="p">(</span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="n">num</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="k">GROUP</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">class_id</span><span class="p">,</span><span class="w"> </span><span class="n">gender</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>练习：</p>
<ol>
<li>
<p>查询查出每个班级的平均分：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">class_id</span><span class="p">,</span><span class="w"> </span><span class="k">AVG</span><span class="p">(</span><span class="n">score</span><span class="p">)</span><span class="w"> </span><span class="n">avgs</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="k">GROUP</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">class_id</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>查出每个班级的男女生的平均分</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">class_id</span><span class="p">,</span><span class="w"> </span><span class="n">gender</span><span class="p">,</span><span class="w"> </span><span class="k">AVG</span><span class="p">(</span><span class="n">score</span><span class="p">)</span><span class="w"> </span><span class="n">avgs</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="k">GROUP</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">class_id</span><span class="p">,</span><span class="w"> </span><span class="n">gender</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
</ol>
<h2 id="多表查询">多表查询</h2>
<p>由于不止存在一张表，当我们需要从多张表查询数据的时候，语法如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">students</span><span class="p">,</span><span class="w"> </span><span class="n">classes</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>查询结果会显示两张表的乘积，也就是暴力累加起来，具体而言：</p>
<ul>
<li>列数为两表的列数之和</li>
<li>行数为两表的行数之积</li>
</ul>
<p>这种粗暴叠加，没有什么实际存在的意义，也<strong>容易产生列名歧义</strong>和<strong>数据爆炸</strong>。针对列名重复的问题，可以通过设置列名Alias来缓解：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- set alias:
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">students</span><span class="p">.</span><span class="n">id</span><span class="w"> </span><span class="n">sid</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">students</span><span class="p">.</span><span class="n">name</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">students</span><span class="p">.</span><span class="n">gender</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">students</span><span class="p">.</span><span class="n">score</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">classes</span><span class="p">.</span><span class="n">id</span><span class="w"> </span><span class="n">cid</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">classes</span><span class="p">.</span><span class="n">name</span><span class="w"> </span><span class="n">cname</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">students</span><span class="p">,</span><span class="w"> </span><span class="n">classes</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>为了简化该操作，避免大量的编写students和classes，sql存在如下的操作：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="c1">-- set table alias as the same time
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="n">s</span><span class="p">.</span><span class="n">id</span><span class="w"> </span><span class="n">sid</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="n">s</span><span class="p">.</span><span class="n">name</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="n">s</span><span class="p">.</span><span class="n">gender</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="n">s</span><span class="p">.</span><span class="n">score</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">c</span><span class="p">.</span><span class="n">id</span><span class="w"> </span><span class="n">cid</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">c</span><span class="p">.</span><span class="n">name</span><span class="w"> </span><span class="n">cname</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="n">s</span><span class="p">,</span><span class="w"> </span><span class="n">classes</span><span class="w"> </span><span class="k">c</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>同样别名的设置不影响条件语句的使用。</p>
<h2 id="连接查询">连接查询</h2>
<h3 id="内联">内联</h3>
<p>和多表查询相对应的，我们真正需要的是将主表中（部分）链接的次表数据链接到主表中，为此我们需要采用连接查询的内联语法将其中的数据取出来。具体的语法表示如下，主要包括：</p>
<ul>
<li>使用Alias避免重名（非必须）</li>
<li>定义所内联的表格<code>inner join</code></li>
<li>选择内联的列<code>on</code></li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">select</span><span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">id</span><span class="p">,</span><span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">class_id</span><span class="p">,</span><span class="w"> </span><span class="k">c</span><span class="p">.</span><span class="n">name</span><span class="w"> </span><span class="n">class_name</span><span class="p">,</span><span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">gender</span><span class="p">,</span><span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">score</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">from</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="n">s</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">inner</span><span class="w"> </span><span class="k">join</span><span class="w"> </span><span class="n">classes</span><span class="w"> </span><span class="k">c</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">on</span><span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">class_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">c</span><span class="p">.</span><span class="n">id</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>同样可以选择加入Where或者Order by字段。</p>
<h3 id="外联">外联</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">id</span><span class="p">,</span><span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">class_id</span><span class="p">,</span><span class="w"> </span><span class="k">c</span><span class="p">.</span><span class="n">name</span><span class="w"> </span><span class="n">class_name</span><span class="p">,</span><span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">gender</span><span class="p">,</span><span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">score</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">students</span><span class="w"> </span><span class="n">s</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">RIGHT</span><span class="w"> </span><span class="k">OUTER</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="n">classes</span><span class="w"> </span><span class="k">c</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">ON</span><span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">class_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">c</span><span class="p">.</span><span class="n">id</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>有RIGHT OUTER JOIN，就有LEFT OUTER JOIN，以及FULL OUTER JOIN。它们的区别是：</p>
<p>INNER JOIN只返回同时存在于两张表的行数据，由于<code>students</code>表的<code>class_id</code>包含1，2，3，<code>classes</code>表的<code>id</code>包含1，2，3，4，所以，INNER JOIN根据条件<code>s.class_id = c.id</code>返回的结果集仅包含1，2，3。</p>
<p>RIGHT OUTER JOIN返回右表都存在的行。如果某一行仅在右表存在，那么结果集就会以<code>NULL</code>填充剩下的字段。</p>
<p>LEFT OUTER JOIN则返回左表都存在的行。如果我们给students表增加一行，并添加class_id=5，由于classes表并不存在id=5的行，所以，LEFT OUTER JOIN的结果会增加一行，对应的<code>class_name</code>是<code>NULL</code>：</p>
<p>FULL OUTER JOIN，它会把两张表的所有记录全部选择出来，并且，自动把对方不存在的列填充为NULL：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220805150740235.png">
    <img alt="image-20220805150740235" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220805150740235.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220805150740235.png" style="display: block; margin: 0 auto;"
      alt="image-20220805150740235"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
]]></content:encoded>
    </item>
    <item>
      <title>SQL Chapter2 安装和基本概念</title>
      <link>https://aikenh.cn/posts/sql2/</link>
      <pubDate>Wed, 03 Aug 2022 10:17:00 +0000</pubDate>
      <guid>https://aikenh.cn/posts/sql2/</guid>
      <description>SQL C2 from Install to use</description>
      <content:encoded><![CDATA[<p>本章节从MySQL的安装到基础使用，<strong>MySQL</strong>本身只是一个SQL接口，它内部还包含多种数据引擎，常用的包括：</p>
<ul>
<li>InnoDB：支持事务的数据库引擎（不知道选啥的时候选他就好）</li>
<li>MyISAM：早期默认，不支持事务</li>
</ul>
<p>接口和引擎的关系好比浏览器和浏览器引擎，切换MySQL引擎不影响自己写的应用程序使用MySQL的接口，由于其开源，也衍生出了各种开源版本（包括针对各种云存储中托管数据库的版本等）</p>
<h2 id="安装mysql">安装MySQL</h2>
<p><strong>Windows</strong>直接官网下载对应的版本就好了，<a href="https://dev.mysql.com/downloads/mysql/" target="_blank" rel="noopener">Community Version</a>
在该超链接进行下载，其他版本就按需下载，按需付费就行。</p>
<p><strong>Linux</strong>下载MySQL：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt-get install mysql-server</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>验证是否下载安装完成：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># 链接服务器</span>
</span></span><span class="line"><span class="cl">mysql
</span></span><span class="line"><span class="cl"><span class="c1"># 登录服务器（需要输入口令）</span>
</span></span><span class="line"><span class="cl">mysql -u root -p </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>成功链接后会变成<code>mysql&gt;</code>，输入<code>exit</code>可以推出MySQL命令行，但是其将仍然在后台运行。</p>
<h2 id="关系模型">关系模型</h2>
<p>关系数据建立在关系模型之上，关系模型本质上就是若干个存储数据的二维表（Excel表），其中</p>
<ul>
<li><strong>每一行称为记录（Record）</strong>：记录是一个逻辑意义上的数据</li>
<li><strong>每一列成为字段（Column）</strong>：同一个表的每一行记录都拥有相同的若干字段，字段需要规定其数据类型，以及是否允许为Null（缺省值）</li>
</ul>
<blockquote>
<p>避免允许Null，不允许可简化查询条件，加快查询速度，也避免程序调用时需要处理Null</p>
</blockquote>
<p>关系数据的<strong>表和表之间的跳转</strong>可以建立“一对多”，“多对一”和“一对一的关系”，这样才能按照应用册灰姑娘徐的逻辑来组织和存储数据，<a href="https://www.liaoxuefeng.com/wiki/1177760294764384/1218728991649984" target="_blank" rel="noopener">通俗的讲</a>
：</p>
<ul>
<li>一个班级可以对应很多学生</li>
<li>多位学生对应同个班级</li>
<li>一个班级对应一个班主任</li>
</ul>
<p>在关系数据库中，关系是通过<strong>主键</strong>和<strong>外键</strong>来维护的。</p>
<h2 id="主键">主键</h2>
<p>在关系数据库中，一张表中的每一行数据被称为一条记录。一条记录就是由多个字段组成的。例如，<code>students</code>表的两行记录：</p>
<table>
  <thead>
      <tr>
          <th>id</th>
          <th>class_id</th>
          <th>name</th>
          <th>gender</th>
          <th>score</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>1</td>
          <td>1</td>
          <td>小明</td>
          <td>M</td>
          <td>90</td>
      </tr>
      <tr>
          <td>2</td>
          <td>1</td>
          <td>小红</td>
          <td>F</td>
          <td>95</td>
      </tr>
  </tbody>
</table>
<p>每一条记录都包含若干定义好的字段。同一个表的所有记录都有相同的字段定义。</p>
<p>而在关系表中，有个很重要的约束：<strong>任意两条记录不能重复</strong>，而不重复指的并非是两条记录不完全相同，而是，能够通过某个字段唯一区分出不同的记录，这个字段成为主键。</p>
<blockquote>
<p>也就是说，如果Name作为主键，那么我们不能存储同名的两个不同的同学。</p>
</blockquote>
<p>由于主键的该特性，通常将主键用来定位和记录，修改主键将造成较大影响，因此我们一般不对主键进行修改。为了避免修改主键，我们避免将主键设置为与任何业务相关的字段（例如身份证、手机等等），避免所有的更新换代和修改造成的不良影响。由此通常使用id来进行主键的存储。</p>
<ul>
<li>自增整数类型：数据库会在插入数据时自动为每一条记录分配一个自增整数，这样我们就完全不用担心主键重复，也不用自己预先生成主键；</li>
<li>全局唯一GUID类型：使用一种全局唯一的字符串作为主键，类似<code>8f55d96b-8acc-4636-8cb8-76bf8abc2f57</code>。GUID算法通过网卡MAC地址、时间戳和随机数保证任意计算机在任意时间生成的字符串都是不同的，大部分编程语言都内置了GUID算法，可以自己预算出主键。</li>
</ul>
<p>大部分应用使用自增整数类型即可，<code>BIGINT NOT NULL AUTO_INCREMENT</code>类型。</p>
<blockquote>
<p>INT自增类型上限差不多是21亿，BIGINT自增类型最多约922亿亿</p>
</blockquote>
<h3 id="联合主键">联合主键</h3>
<p>关系数据库实际上还允许通过多个字段唯一标识记录，即两个或更多的字段都设置为主键，这种主键被称为联合主键。对于联合主键，允许一列有重复，只要不是所有主键列都重复即可：</p>
<p>没有必要的情况下，尽量不使用联合主键，其带来关系表的复杂度的上升。</p>
<h2 id="外键">外键</h2>
<blockquote>
<p>以学生和班级的数据集为例对外键进行分析和介绍。</p>
</blockquote>
<p>主键唯一标识记录，我们可以在students中确认任意一个学生的记录，在Classes表中确定任何一个班级的位置等。而一个班级可以有多个学生，这种一对多关系，对应的表的映射的实现，我们需要在<code>students</code>表中加入<code>class_id</code>，让它的值与<code>classes</code>表中的某条记录相对应。</p>
<table>
  <thead>
      <tr>
          <th>id</th>
          <th>name</th>
          <th>other columns</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>1</td>
          <td>一班</td>
          <td>…</td>
      </tr>
      <tr>
          <td>2</td>
          <td>二班</td>
          <td>…</td>
      </tr>
  </tbody>
</table>
<p>这样就可以通过<code>class_id</code>定位出<code>students</code>和<code>classes</code>的对应关系，通过<code>class_id</code>字段，将<code>students</code>和<code>classes</code>表连接起来，这种列（字段）被称为<strong>外键</strong>。</p>
<p>外键并不是通过列名实现的，而是通过定义外键约束实现的：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>SQL</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-SQL" data-lang="SQL"><span class="line"><span class="cl"><span class="k">ALTER</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">students</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">ADD</span><span class="w"> </span><span class="k">CONSTRAINT</span><span class="w"> </span><span class="n">fk_class_id</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FOREIGN</span><span class="w"> </span><span class="k">KEY</span><span class="w"> </span><span class="p">(</span><span class="n">class_id</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">REFERENCES</span><span class="w"> </span><span class="n">classes</span><span class="w"> </span><span class="p">(</span><span class="n">id</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>其中，外键约束的名称<code>fk_class_id</code>可以任意，<code>FOREIGN KEY (class_id)</code>指定了<code>class_id</code>作为外键，<code>REFERENCES classes (id)</code>指定了这个外键将关联到<code>classes</code>表的<code>id</code>列（即<code>classes</code>表的主键）。</p>
<p>通过定义外键约束，关系数据库可以保证无法插入无效的数据。即如果<code>classes</code>表不存在<code>id=99</code>的记录，<code>students</code>表就无法插入<code>class_id=99</code>的记录。</p>
<p>由于外键约束会降低数据库的性能，大部分互联网应用程序为了追求速度，并不设置外键约束，而是仅靠应用程序自身来保证逻辑的正确性。这种情况下，<code>class_id</code>仅仅是一个普通的列，只是它起到了外键的作用而已。</p>
<p>删除外键约束也是通过<code>ALTER TABLE</code>实现的：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">ALTER</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">students</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">DROP</span><span class="w"> </span><span class="k">FOREIGN</span><span class="w"> </span><span class="k">KEY</span><span class="w"> </span><span class="n">fk_class_id</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>多对多是通过一个中间表实现的。</p>
<p>一对一还要建表是为了避免缺省值</p>
<blockquote>
<p>“关系数据库通过外键可以实现一对多、多对多和一对一的关系。外键既可以通过数据库来约束，也可以不设置约束，仅依靠应用程序的逻辑来保证。”</p>
</blockquote>
<h2 id="索引">索引</h2>
<p>为了快速搜索数据，需要对（用于搜索的）特定关键词建立索引，通过索引进行预排序，帮助快速定位到符合条件的记录来加快查询速度。</p>
<p>如果我们希望对学生的成绩<code>score</code>建立索引，方便对<code>score</code>进行快速查找：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">ALTER</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">students</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">ADD</span><span class="w"> </span><span class="k">INDEX</span><span class="w"> </span><span class="n">idx_score</span><span class="p">(</span><span class="n">score</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>使用<code>ADD INDEX idx_score (score)</code>就创建了一个名称为<code>idx_score</code>，使用列<code>score</code>的索引。索引名称是任意的，索引如果有多列，可以在括号里依次写上，例如：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">ALTER</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">students</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">ADD</span><span class="w"> </span><span class="k">INDEX</span><span class="w"> </span><span class="n">idx_name_score</span><span class="p">(</span><span class="n">score</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>索引的效率取决于散列的程度，如果值越分散，索引效率越高，如果存在大量的重复值（像性别），创建索引就没有意义。</p>
<h3 id="优缺点">优缺点</h3>
<p>可以对同一张表建立多个索引，但是索引的建立会带来如下的优缺点：</p>
<ul>
<li>提高了查询效率</li>
<li>插入、更新、删除记录的时候需要更新，越多索引修改的速度就越慢</li>
</ul>
<h3 id="唯一索引">唯一索引</h3>
<p>具有业务意义，如身份证之类的唯一标识，不适合作为主键，但是可以构建唯一索引，其具备最高的索引效率。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">ALTER</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">students</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">ADD</span><span class="w"> </span><span class="k">UNIQUE</span><span class="w"> </span><span class="k">INDEX</span><span class="w"> </span><span class="n">uni_name</span><span class="p">(</span><span class="n">name</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>也可以只对某一列添加一个唯一约束而不创建唯一索引：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sql</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">ALTER</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">students</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">ADD</span><span class="w"> </span><span class="k">CONSTRAINT</span><span class="w"> </span><span class="n">uni_name</span><span class="w"> </span><span class="k">UNIQUE</span><span class="w"> </span><span class="p">(</span><span class="n">name</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在这种情况下，没有建立索引，但是具备唯一性约束。</p>
]]></content:encoded>
    </item>
    <item>
      <title>SQL Chapter1 Introduce</title>
      <link>https://aikenh.cn/posts/sql1/</link>
      <pubDate>Tue, 02 Aug 2022 11:17:04 +0000</pubDate>
      <guid>https://aikenh.cn/posts/sql1/</guid>
      <description>学习数据库的标准处理语言SQL C1</description>
      <content:encoded><![CDATA[<p>SQL相关参考资料：尊重一下<a href="https://www.runoob.com/sql/sql-tutorial.html" target="_blank" rel="noopener">菜鸟教程</a>
 ，该教程中的文档相对简练和入门，<a href="https://www.w3school.com.cn/sql/sql_intro.asp" target="_blank" rel="noopener">W3School</a>
的资料好像就是菜鸟教程的；其次，<a href="https://www.liaoxuefeng.com/wiki/1177760294764384" target="_blank" rel="noopener">廖雪峰</a>
的SQL教程网站，也应该比较适合入门，对比后选择一个进行学习。</p>
<p>围绕SQL是什么、有什么用、和怎么用来学习。</p>
<p>利用廖雪峰的教程来进行学习，因为其具备在线运行和测试的功能。</p>
<h2 id="sql是什么">SQL是什么</h2>
<p>SQL：Structured Query Language（结构化查询语言）用于访问和操作数据库系统：查询、添加、更新、删除、管理、维护。不同的数据库，都支持SQL。</p>
<p>&ldquo;SQL就是访问和处理关系数据库的计算机标准语言“，无论使用什么编程语言编写程序，当我们涉及到<strong>操作关系数据库</strong>之时，就需要使用SQL，其中，最流行的开源数据库为MySQL。</p>
<p>同时，现今还存在非SQL的数据库，也就是NoSQL数据库，例如：MongoDB、Cassandra、Dynamo都属于非关系数据库。</p>
<p>而SQL在当今仍然承担各种应用程序的核心数据存储，与NoSQL（作为SQL数据库的补充）相辅相成。</p>
<blockquote>
<p>虽然SQL已经被ANSI组织定义为标准，不幸地是，各个不同的数据库对标准的SQL支持不太一致。并且，大部分数据库都在标准的SQL上做了扩展。也就是说，如果只使用标准SQL，理论上所有数据库都可以支持，但如果使用某个特定数据库的扩展SQL，换一个数据库就不能执行了。例如，Oracle把自己扩展的SQL称为PL/SQL，Microsoft把自己扩展的SQL称为T-SQL。</p>
</blockquote>
<p>&ldquo;现实情况是，如果我们只使用标准SQL的核心功能，那么所有数据库通常都可以执行。不常用的SQL功能，不同的数据库支持的程度都不一样。而各个数据库支持的各自扩展的功能，通常我们把它们称之为“方言”。&rdquo;</p>
<p>SQL定义了这几种<strong>操作数据库的能力：</strong></p>
<ul>
<li>DDL（Data Definition Language）：允许用户定义数据，也就是创建表、删除表、修改表结构这些操作。通常，DDL由数据库管理员执行。</li>
<li>DML（Data Manipulation Language）：为用户提供添加、删除、更新数据的能力，这些是应用程序对数据库的日常操作。</li>
<li>DQL（Data Query Language）：允许用户查询数据，这也是通常最频繁的数据库日常操作。</li>
</ul>
<p><strong>SQL的语法特点</strong>：</p>
<p><strong>SQL语言关键字不区分大小写</strong>！！！
但是，针对不同的数据库，对于表名和列名，有的数据库区分大小写，有的数据库不区分大小写。同一个数据库，有的在Linux上区分大小写，有的在Windows上不区分大小写。</p>
<h2 id="数据库">数据库</h2>
<h3 id="为什么需要数据库">为什么需要数据库</h3>
<p>为什么需要数据库，实际上就是面对大量的数据储备，进行更有效的管理，实现</p>
<ul>
<li>统一数据格式（接口）管理，实现统一的读写文件和解析方法。</li>
<li>在数据库中快速查询并获取指定数据。</li>
</ul>
<p>因此借由数据库来专门管理数据，统一结构（接口），读写，以及搜索流程。这样，当应用需要使用数据的时候，就可简化流程如图所示：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220803124419.png">
    <img alt="database" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220803124419.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220803124419.png" style="display: block; margin: 0 auto;"
      alt="database"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="数据库的数据架构">数据库的数据架构</h3>
<p>数据库按照数据架构来组织、存储和管理数据，主要有以下三种模型结构：</p>
<ul>
<li>层次模型</li>
<li>网状模型</li>
<li>关系模型</li>
</ul>
<p>层次模型顾名思义是“上下级”的层次关系来组织数据的方式，类似树状结构：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220803140947.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220803140947.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220803140947.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>网状结构则是把每个数据节点和其他诸多节点进行链接，数据结构像是道路的网络。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220803141041.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220803141041.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220803141041.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>关系模型则是以矩阵的形式对数据进行存储，任何数据通过行列坐标来唯一确定。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220803142004.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220803142004.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220803142004.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>最终，<strong>基于关系模型的关系数据库</strong>成为了绝对的主流，因其使用和理解起来最为简单。其形式可理解为多元属性的<a href="https://baike.baidu.com/item/%E7%AC%9B%E5%8D%A1%E5%B0%94%E9%9B%86/4542998" target="_blank" rel="noopener">笛卡尔集</a>
，也就是每条数据是由 n 元（n 个属性值）构成，而由这些数据的集合构成数据集，每个属性值也能对应更为详细的表。以班级为例，一个班级的学生可以用一个表格存起来，如下：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: left">ID</th>
          <th style="text-align: left">姓名</th>
          <th style="text-align: left">班级 ID</th>
          <th style="text-align: left">性别</th>
          <th style="text-align: left">年龄</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: left">1</td>
          <td style="text-align: left">小明</td>
          <td style="text-align: left">201</td>
          <td style="text-align: left">M</td>
          <td style="text-align: left">9</td>
      </tr>
      <tr>
          <td style="text-align: left">2</td>
          <td style="text-align: left">小红</td>
          <td style="text-align: left">202</td>
          <td style="text-align: left">F</td>
          <td style="text-align: left">8</td>
      </tr>
      <tr>
          <td style="text-align: left">3</td>
          <td style="text-align: left">小军</td>
          <td style="text-align: left">202</td>
          <td style="text-align: left">M</td>
          <td style="text-align: left">8</td>
      </tr>
      <tr>
          <td style="text-align: left">4</td>
          <td style="text-align: left">小白</td>
          <td style="text-align: left">201</td>
          <td style="text-align: left">F</td>
          <td style="text-align: left">9</td>
      </tr>
  </tbody>
</table>
<p>其中班级 ID 可对应另一个班级表：</p>
<table>
  <thead>
      <tr>
          <th>ID</th>
          <th>名称</th>
          <th>班主任</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>201</td>
          <td>二年级一班</td>
          <td>王老师</td>
      </tr>
      <tr>
          <td>202</td>
          <td>二年级二班</td>
          <td>李老师</td>
      </tr>
  </tbody>
</table>
<p>通过给定一个班级名称，可以查到一条班级记录，根据班级ID，又可以查到多条学生记录，这样，二维表之间就通过ID映射建立了“一对多”关系。</p>
<p>对于每个关系表，每一列除了需要定义名称之外，还需要指定数据类型，数据类型包括数值、字符串、时间等（具体建议<a href="https://www.runoob.com/sql/sql-datatypes-general.html" target="_blank" rel="noopener">查表</a>
）</p>
<h3 id="主流关系数据库">主流关系数据库</h3>
<ul>
<li>商用数据库，例如：Oracle，SQL Server，DB2等；</li>
<li>开源数据库，例如：MySQL，PostgreSQL等；</li>
<li>桌面数据库，以微软Access为代表，适合桌面应用程序使用；</li>
<li>嵌入式数据库，以Sqlite为代表，适合手机应用和桌面程序。</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Windows Configuration03 LAN sharing</title>
      <link>https://aikenh.cn/posts/%E5%B1%80%E5%9F%9F%E7%BD%91%E6%96%87%E4%BB%B6%E5%85%B1%E4%BA%AB/</link>
      <pubDate>Sun, 31 Jul 2022 23:43:00 +0000</pubDate>
      <guid>https://aikenh.cn/posts/%E5%B1%80%E5%9F%9F%E7%BD%91%E6%96%87%E4%BB%B6%E5%85%B1%E4%BA%AB/</guid>
      <description>windows设置文件共享，以及全平台如何访问</description>
      <content:encoded><![CDATA[<p>在同一个局域网（像是链接同一个wifi的环境）中，设置共享的文件夹或者磁盘，可提升文件分享的效率和速度，特别适用于与女朋友合租、与兄弟合租的情景。</p>
<h2 id="win-系统开放共享权限">Win 系统开放共享权限</h2>
<p>Windows的设置首先要在控制面板中开启共享功能：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220801160336296.png">
    <img alt="image-20220801160336296" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220801160336296.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220801160336296.png" style="display: block; margin: 0 auto;"
      alt="image-20220801160336296"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>针对专用网络开启</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220801161142132.png">
    <img alt="image-20220801161142132" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220801161142132.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220801161142132.png" style="display: block; margin: 0 auto;"
      alt="image-20220801161142132"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>为了信息和数据安全关闭来宾和公用，并开启加密</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220801161340594.png">
    <img alt="image-20220801161340594" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220801161340594.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220801161340594.png" style="display: block; margin: 0 auto;"
      alt="image-20220801161340594"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>基于该设置，在访问共享文件夹之时，需要输入账号和密码。</p>
<h2 id="win-共享文件夹设置">Win 共享文件夹设置</h2>
<p>直接使用默认的共享功能可以方便设置，但是存在可访问父级文件夹的 bug，建议设置好用户后使用。</p>
<p>如果操作得当可以使用高级共享功能来创建更为安全的文件夹共享。</p>
<p>使用高级共享中的设置来定义权限Everyone（是否允许修改等其他权限）</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220801162822427.png">
    <img alt="image-20220801162822427" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220801162822427.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220801162822427.png" style="display: block; margin: 0 auto;"
      alt="image-20220801162822427"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>至此，完成了文件夹和文件的共享设置，使用同样的设置，便可以在LAN中的其他设备访问开放共享的文件夹。</p>
<h3 id="共享用户创建">共享用户创建</h3>
<p>可以在默认的共享设置中设置权限的时候，选择设置新用户，跳过使用 Microsoft 账号，创建本地账号，后面共享链接的时候就可以用该账号登录了。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322092927.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322092927.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322092927.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>然后选择管理其他账户 
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322092954.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322092954.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322092954.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
，然后选择添加新用户-&gt; 添加账户即可。</p>
<h2 id="linux-共享文件夹设置">Linux 共享文件夹设置</h2>
<p>设置 Linux 的文件夹共享，安装对应的 Samba 来启动 SMB 文件共享（需要注意的是，这一步安装不能使用远程桌面进行）</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230625181635.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230625181635.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230625181635.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>设置好对应的文件读写权限，同时使用下列命令设置好允许访问 smb 文件夹的用户：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo smbpasswd -a &lt;username&gt;</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><code>&lt;username&gt;</code> 需要为 linux 的有效用户，设置好 SMB 账号密码即可开启完整的访问服务。</p>
<h2 id="各平台访问共享文件夹">各平台访问共享文件夹</h2>
<h3 id="windows-访问">windows 访问</h3>
<p>使用以下的方式访问共享文件夹：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span></span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code>\\192.168.31.108\\Folder</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以使用<code>\\localhost</code>在资源管理器中访问《网络》中《我的共享文件夹》，确保当前网络为<strong>专用</strong>的情况下，可以打开另外终端资源管理器中的《网络》来访问当前共享文件夹。</p>
<p>经测试，文件访问和读取的速度较快，在带宽充足的情况下，能够取代 U 盘等进行文件的传输和共享，也能实现视频流的实时播放。</p>
<h3 id="ios-访问">ios 访问</h3>
<p>在默认的文件 APP 中，连接服务器，连接到 pc 的 ip 地址，用指定的账户登录即可。</p>
<h3 id="mac-访问">mac 访问</h3>
<p>在访达中选择前往，然后选择连接服务器，然后选中局域网的 IP 并输入指定的账号密码即可登录。</p>
<h3 id="linux-访问">Linux 访问</h3>
<p><a href="https://blog.csdn.net/weixin_36118049/article/details/116648793" target="_blank" rel="noopener">linux开机挂载文件夹,Linux开机挂载windows共享文件夹_正妻空母加贺桑的博客-CSDN博客</a>
</p>
<p>【交互界面】方法 1：在 File Manager 里面选择 other Location 中的 Connect to Server，连接到 windows 的 SMB 服务器即可。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230625180602.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230625180602.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230625180602.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>【推荐】方法 2：使用手动挂载命令，将 windows 的共享文件夹挂载到指定目录下。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo mount -t cifs //192.168.31.201/&lt;share dir&gt; &lt;local-position&gt; -o <span class="nv">username</span><span class="o">=</span><span class="s1">&#39;username&#39;</span>,password<span class="o">=</span><span class="s1">&#39;passwd&#39;</span>,vers<span class="o">=</span>2.0</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>【成功】方法 2.1：使用<a href="https://www.cnblogs.com/52php/p/5677805.html" target="_blank" rel="noopener">开机启动脚本</a>
 <code>/etc/rc.local</code> 开机执行上述脚本即可，<a href="https://m.isolves.com/it/rj/czxt/linux/2022-06-17/55976.html" target="_blank" rel="noopener">Ubuntu 22.04 LTS 不用再自己写rc-local.service了-简易百科 (isolves.com)</a>
 ，原本系统中没有 <code>rc.local</code> 文件，但是 Ubuntu 中已经无需自己编写，但是需要新建后赋予其执行权限</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo chmod +x /etc/rc.local</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这里需要注意的是，编写挂载脚本的时候，因为树莓派在刚开机的时候挂载会失败，所以需要引入 sleep 一段时间。具体的操作流程如下：</p>
<ul>
<li>创建脚本文件 <code>startup.sh</code> 在任意位置，内容参考手动挂载命令，在这之前添加 sleep。</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sleep <span class="m">30</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 下面两者选一个用即可</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 选项1 使用方法2.手动挂载命令挂载</span>
</span></span><span class="line"><span class="cl">sudo mount -t cifs //192.168.31.201/&lt;share dir&gt; &lt;local-position&gt; -o <span class="nv">username</span><span class="o">=</span><span class="s1">&#39;username&#39;</span>,password<span class="o">=</span><span class="s1">&#39;passwd&#39;</span>,vers<span class="o">=</span>2.0
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 选项2 使用方法2.3 已经在fstab中加入挂载的命令</span>
</span></span><span class="line"><span class="cl">sudo mount -a</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>在 <code>rc.local</code> 的 exit0之前添加调用执行该脚本</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">...
</span></span><span class="line"><span class="cl">...
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">sudo sh /&lt;path-to-your-script&gt;/startup.sh
</span></span><span class="line"><span class="cl"><span class="nb">exit</span> <span class="m">0</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果失败了可以尝试 chmod +x startup.Sh 修改成可执行。</p>
<p>【成功】方法 2.2：<a href="https://www.80tm.com/2022/12/17/ubuntu%E5%BC%80%E6%9C%BA%E8%87%AA%E5%8A%A8%E8%BF%90%E8%A1%8C%E5%91%BD%E4%BB%A4/" target="_blank" rel="noopener">加入开机启动项</a>
，在 <code>/etc/init.d</code> 中编写需要开机启动的脚本，然后执行以下的命令加入开机启动中：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo update-rc.d xxx.sh defaults <span class="m">90</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>最后一个数字是脚本启动的顺序，数字越大，执行越晚，重启即可完成测试，以下命令可以查看全部服务列表：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo service --status-all</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>卸载启动脚本的方法：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo update-rc.d -f xxx.sh remove</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>【成功一半】方法 2.3：使用自动挂载命令，修改 <a href="https://www.cnblogs.com/arnoldlu/p/11613842.html" target="_blank" rel="noopener">fstab</a>
，将以下的命令添加到该文件下面即可生效：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">//192.168.31.201/&lt;share dir&gt; /mnt/windows-share cifs username=&#39;username&#39;,password=&#39;passwd&#39; 0 0 </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果要卸载网络共享目录使用以下命令：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo umount &lt;local-postion&gt;</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以通过 <code>df -h</code> 查看挂载是否成功。</p>
<p>【可选】方法 3: 要进入 smb 的命令操作空间</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 安装Smbclient</span>
</span></span><span class="line"><span class="cl">sudo apt-get install smbclinent</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>安装好后，就可以访问共享的文件夹，这样会进入 smb 的命令操作空间</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">smbclient --user<span class="o">=</span>share //192.168.31.198/share</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script>]]></content:encoded>
    </item>
    <item>
      <title>Windows Configuration02 Terminal</title>
      <link>https://aikenh.cn/posts/windowsterminal/</link>
      <pubDate>Sat, 30 Jul 2022 10:03:26 +0000</pubDate>
      <guid>https://aikenh.cn/posts/windowsterminal/</guid>
      <description>&lt;h2 id=&#34;config-windows-terminal-in-win11&#34;&gt;Config Windows Terminal in Win11&lt;/h2&gt;
&lt;h3 id=&#34;install-安装&#34;&gt;Install 安装&lt;/h3&gt;
&lt;p&gt;windows terminal 在 win11 已经自带，无需安装，如果需要安装的话在 Microsoft Store 下载即可，默认的 terminal 在中文环境中可能要搜索 windows 终端。&lt;/p&gt;
&lt;h3 id=&#34;baisc-基础设置&#34;&gt;Baisc 基础设置&lt;/h3&gt;
&lt;p&gt;新版的 Windows Terminal 有了图形化配置界面，因此配置简单和直观了不少，该部分就简要的介绍一下基础的设置。通过 Ctrl+,  或者下拉菜单可以打开设置页面。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;完成每一部分的修改后记得保存&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;首先在&lt;strong&gt;默认的终端应用&lt;/strong&gt;程序中选择 windows 终端，将其作为默认的终端模拟器（terminal simulator），启动的地方，可以设置默认的配置文件，这里后续会用到。&lt;/p&gt;
&lt;p&gt;
&lt;div class=&#34;post-img-view&#34;&gt;
  &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322083142.png&#34;&gt;
    &lt;img alt=&#34;image.png&#34; loading=&#34;lazy&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322083142.png&#34;class=&#34;responsive-image&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322083142.png&#34; style=&#34;display: block; margin: 0 auto;&#34;
      alt=&#34;image.png&#34;  /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;script&gt;
  document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
      var images = document.querySelectorAll(&#34;.responsive-image&#34;);
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + &#34;px&#34;;
      });
  });
&lt;/script&gt;
&lt;/p&gt;
&lt;p&gt;接着交互选项卡中启用&lt;strong&gt;复制粘贴&lt;/strong&gt;功能，该功能可以避免在和终端或者 WSL，vim 交互的时候一些复制粘贴的相关问题和配置，（记得点击保存）&lt;/p&gt;
&lt;p&gt;
&lt;div class=&#34;post-img-view&#34;&gt;
  &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322083832.png&#34;&gt;
    &lt;img alt=&#34;image.png&#34; loading=&#34;lazy&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322083832.png&#34;class=&#34;responsive-image&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322083832.png&#34; style=&#34;display: block; margin: 0 auto;&#34;
      alt=&#34;image.png&#34;  /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;script&gt;
  document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
      var images = document.querySelectorAll(&#34;.responsive-image&#34;);
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + &#34;px&#34;;
      });
  });
&lt;/script&gt;
&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h2 id="config-windows-terminal-in-win11">Config Windows Terminal in Win11</h2>
<h3 id="install-安装">Install 安装</h3>
<p>windows terminal 在 win11 已经自带，无需安装，如果需要安装的话在 Microsoft Store 下载即可，默认的 terminal 在中文环境中可能要搜索 windows 终端。</p>
<h3 id="baisc-基础设置">Baisc 基础设置</h3>
<p>新版的 Windows Terminal 有了图形化配置界面，因此配置简单和直观了不少，该部分就简要的介绍一下基础的设置。通过 Ctrl+,  或者下拉菜单可以打开设置页面。</p>
<p><strong>完成每一部分的修改后记得保存</strong></p>
<p>首先在<strong>默认的终端应用</strong>程序中选择 windows 终端，将其作为默认的终端模拟器（terminal simulator），启动的地方，可以设置默认的配置文件，这里后续会用到。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322083142.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322083142.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322083142.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>接着交互选项卡中启用<strong>复制粘贴</strong>功能，该功能可以避免在和终端或者 WSL，vim 交互的时候一些复制粘贴的相关问题和配置，（记得点击保存）</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322083832.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322083832.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322083832.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>该选项卡中还有关闭多窗口时是否提示，可以按需关闭或开启。</p>
<p>紧接着外观选项卡中打开亚克力材料，隐藏标题栏以及深色主题（个人觉得浅色主题和终端界面没法很好的融合在一起）</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322084423.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322084423.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322084423.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>然后可以为终端提供配色方案，结合后续会提到的透明窗格来使用，默认的配置文件中，我比较推荐 Tango Dark 和 One Half Dark 来搭配使用，但是默认的配置又以下的问题：</p>
<ul>
<li>图形化配置界面方便自定义但是不太方便导入他人的配置</li>
<li>默认的配置方案相对较少</li>
</ul>
<p>因此我们还是使用 JSON 的方式来导入他人的配置文件，配置文件可以参考以下链接获取：</p>
<ol>
<li><a href="https://windowsterminalthemes.dev/" target="_blank" rel="noopener">Windows Terminal Themes</a>
</li>
<li><a href="https://terminalsplash.com/" target="_blank" rel="noopener">&gt;_TerminalSplash - Windows Terminal Themes</a>
</li>
</ol>
<p>在设置界面的左下角打开 JSON 文件</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322085654.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322085654.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322085654.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>里面找到 scheme 部分，可以看到这里和我们上述链接获取到的格式是一致的，在这里添加配置。添加后可以看到主题就在配色方案中出现即可，后续在各个具体 terminal 的配置文件中进行设置。</p>
<h3 id="configs-配置文件设置">Configs 配置文件设置</h3>
<p>在配置文件下可以看到针对每一个 Shell（CMD、Poweshell、WSL） 都会有一套配置文件，如果全都分开设置的话非常的麻烦，因此除了独有设置（蓝框），像外观和一些基础的交互行为（红框），都通过默认值来进行<strong>统一管理</strong>。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322091239.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322091239.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322091239.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>首先进入<strong>外观选项</strong>，主要需要设置的有以下的几项：配色方案、字体、光标形状、背景图像、不透明度和亚克力材料。</p>
<ul>
<li>配色方案根据上面我们导入的进行选择即可</li>
<li>字体选择 <a href="https://www.nerdfonts.com/" target="_blank" rel="noopener">nerd font</a>
 可以解决终端中部分图标渲染不出来的问题</li>
<li>光标形状和背景图像按照自己的需求进行设置即可</li>
<li>推荐启用亚克力材料和不透明度（美化的灵魂）</li>
</ul>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322091845.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322091845.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322091845.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>接着进入<strong>高级选项</strong>，这里主要将铃声通知样式关闭，太吵了。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322092308.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322092308.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322092308.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>独有配置部分我们以 WSL 为例说一下主要需要设置哪些，除了名称、图标等还可以设置以下的：</p>
<ul>
<li>CMD 和 PS 可以设置以管理员身份运行</li>
<li>WSL 之类的我们可以设置其中的启动目录</li>
<li>命令行部分即选择执行的是哪个 Shell 以及是否指定用户</li>
<li>针对一些平时用不到的可以从下拉菜单中隐藏。</li>
</ul>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322092656.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322092656.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230322092656.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>Done for now</p>
<h2 id="config-terminal-by-json已废弃">Config Terminal By Json（已废弃）</h2>
<p>内测时期的 Terminal 需要通过 JSON 来进行配置，同时也不支持右键菜单中打开，因此有了这个配置，但是随着 terminal 图形化设置界面的完善，该部分配置已经废弃。</p>
<p><strong>Install</strong> ：Windows Store</p>
<p><strong>添加 Terminal 到右键菜单</strong>：</p>
<p>参考：<a href="https://zhuanlan.zhihu.com/p/137595941" target="_blank" rel="noopener">Windows Terminal 完美配置 </a>
 中的右键菜单部分：<a href="https://github.com/lextm/windowsterminal-shell/" target="_blank" rel="noopener">Install/uninstall scripts for Windows Terminal context menu items </a>
</p>
<p>注意，这里涉及到注册表修改的操作，所以我们需要在修改注册表之间建立注册表还原点。</p>
<p><strong>Basic Config</strong>：</p>
<p>新版本的 Terminal 中大部分的配置都已经有了 UI 了，配置起来还是比较方便的，其实主要的配置直接在设置面板里设置就可以了。这里以早期版本的配置文件设置为例：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>json</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;$schema&#34;</span><span class="p">:</span> <span class="s2">&#34;https://aka.ms/terminal-profiles-schema&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;actions&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;command&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;action&#34;</span><span class="p">:</span> <span class="s2">&#34;copy&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;singleLine&#34;</span><span class="p">:</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;keys&#34;</span><span class="p">:</span> <span class="s2">&#34;ctrl+c&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;find&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;keys&#34;</span><span class="p">:</span> <span class="s2">&#34;ctrl+shift+f&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;paste&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;keys&#34;</span><span class="p">:</span> <span class="s2">&#34;ctrl+v&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;command&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;action&#34;</span><span class="p">:</span> <span class="s2">&#34;splitPane&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;split&#34;</span><span class="p">:</span> <span class="s2">&#34;auto&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;splitMode&#34;</span><span class="p">:</span> <span class="s2">&#34;duplicate&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;keys&#34;</span><span class="p">:</span> <span class="s2">&#34;alt+shift+d&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;alwaysShowTabs&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;copyFormatting&#34;</span><span class="p">:</span> <span class="s2">&#34;rtf&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;copyOnSelect&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;defaultProfile&#34;</span><span class="p">:</span> <span class="s2">&#34;{07b52e3e-de2c-5db4-bd2d-ba144ed6c273}&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;initialCols&#34;</span><span class="p">:</span> <span class="mi">130</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;initialRows&#34;</span><span class="p">:</span> <span class="mi">35</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;launchMode&#34;</span><span class="p">:</span> <span class="s2">&#34;default&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;profiles&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;defaults&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;acrylicOpacity&#34;</span><span class="p">:</span> <span class="mf">0.69999999999999996</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;closeOnExit&#34;</span><span class="p">:</span> <span class="s2">&#34;graceful&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;colorScheme&#34;</span><span class="p">:</span> <span class="s2">&#34;AdventureTime&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;font&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;face&#34;</span><span class="p">:</span> <span class="s2">&#34;FiraCode Nerd Font&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;historySize&#34;</span><span class="p">:</span> <span class="mi">9001</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;padding&#34;</span><span class="p">:</span> <span class="s2">&#34;5, 5, 20, 25&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;snapOnInput&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;startingDirectory&#34;</span><span class="p">:</span> <span class="s2">&#34;.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;useAcrylic&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;list&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;backgroundImage&#34;</span><span class="p">:</span> <span class="s2">&#34;C:\\Users\\Aiken\\Pictures\\Camera Roll\\a560083febb425e04ba0a86a7851c51dc2b417a4.png&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;backgroundImageOpacity&#34;</span><span class="p">:</span> <span class="mf">0.26000000000000001</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;colorScheme&#34;</span><span class="p">:</span> <span class="s2">&#34;purplepeter&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;commandline&#34;</span><span class="p">:</span> <span class="s2">&#34;powershell.exe&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;font&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;face&#34;</span><span class="p">:</span> <span class="s2">&#34;FiraCode Nerd Font Mono Retina&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="p">},</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;guid&#34;</span><span class="p">:</span> <span class="s2">&#34;{61c54bbd-c2c6-5271-96e7-009a87ff44bf}&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;hidden&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;Windows PowerShell&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;commandline&#34;</span><span class="p">:</span> <span class="s2">&#34;cmd.exe&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;guid&#34;</span><span class="p">:</span> <span class="s2">&#34;{0caa0dad-35be-5f56-a8ff-afceeeaa6101}&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;hidden&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;CMD&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;guid&#34;</span><span class="p">:</span> <span class="s2">&#34;{b453ae62-4e3d-5e58-b989-0a998ec441b8}&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;hidden&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;Azure Cloud Shell&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;source&#34;</span><span class="p">:</span> <span class="s2">&#34;Windows.Terminal.Azure&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;colorScheme&#34;</span><span class="p">:</span> <span class="s2">&#34;Banana Blueberry&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;commandline&#34;</span><span class="p">:</span> <span class="s2">&#34;ssh root@202.117.43.196 -p 23076&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;guid&#34;</span><span class="p">:</span> <span class="s2">&#34;{44257ed0-90f8-41a1-bad0-2c637012ce40}&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;hidden&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;icon&#34;</span><span class="p">:</span> <span class="s2">&#34;ms-appx:///ProfileIcons/{9acb9455-ca41-5af7-950f-6bca1bc9722f}.png&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;202.117.43.196&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;startingDirectory&#34;</span><span class="p">:</span> <span class="s2">&#34;.&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;acrylicOpacity&#34;</span><span class="p">:</span> <span class="mf">0.68999999999999995</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;antialiasingMode&#34;</span><span class="p">:</span> <span class="s2">&#34;cleartype&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;backgroundImage&#34;</span><span class="p">:</span> <span class="s2">&#34;desktopWallpaper&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;backgroundImageOpacity&#34;</span><span class="p">:</span> <span class="mf">0.20000000000000001</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;colorScheme&#34;</span><span class="p">:</span> <span class="s2">&#34;purplepeter&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;commandline&#34;</span><span class="p">:</span> <span class="s2">&#34;wsl.exe ~&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;cursorShape&#34;</span><span class="p">:</span> <span class="s2">&#34;underscore&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;experimental.retroTerminalEffect&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;font&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;face&#34;</span><span class="p">:</span> <span class="s2">&#34;FiraCode Nerd Font&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="p">},</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;guid&#34;</span><span class="p">:</span> <span class="s2">&#34;{07b52e3e-de2c-5db4-bd2d-ba144ed6c273}&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;hidden&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;intenseTextStyle&#34;</span><span class="p">:</span> <span class="s2">&#34;all&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;Linux20.04&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;padding&#34;</span><span class="p">:</span> <span class="s2">&#34;10&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;source&#34;</span><span class="p">:</span> <span class="s2">&#34;Windows.Terminal.Wsl&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;startingDirectory&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;tabTitle&#34;</span><span class="p">:</span> <span class="kc">null</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;schemes&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;background&#34;</span><span class="p">:</span> <span class="s2">&#34;#1F1D45&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;black&#34;</span><span class="p">:</span> <span class="s2">&#34;#050404&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;blue&#34;</span><span class="p">:</span> <span class="s2">&#34;#0F4AC6&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;brightBlack&#34;</span><span class="p">:</span> <span class="s2">&#34;#4E7CBF&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;brightBlue&#34;</span><span class="p">:</span> <span class="s2">&#34;#1997C6&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;brightCyan&#34;</span><span class="p">:</span> <span class="s2">&#34;#C8FAF4&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;brightGreen&#34;</span><span class="p">:</span> <span class="s2">&#34;#9EFF6E&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;brightPurple&#34;</span><span class="p">:</span> <span class="s2">&#34;#9B5953&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;brightRed&#34;</span><span class="p">:</span> <span class="s2">&#34;#FC5F5A&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;brightWhite&#34;</span><span class="p">:</span> <span class="s2">&#34;#F6F5FB&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;brightYellow&#34;</span><span class="p">:</span> <span class="s2">&#34;#EFC11A&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;cursorColor&#34;</span><span class="p">:</span> <span class="s2">&#34;#FFFFFF&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;cyan&#34;</span><span class="p">:</span> <span class="s2">&#34;#70A598&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;foreground&#34;</span><span class="p">:</span> <span class="s2">&#34;#F8DCC0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;green&#34;</span><span class="p">:</span> <span class="s2">&#34;#4AB118&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;AdventureTime&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;purple&#34;</span><span class="p">:</span> <span class="s2">&#34;#665993&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;red&#34;</span><span class="p">:</span> <span class="s2">&#34;#BD0013&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;selectionBackground&#34;</span><span class="p">:</span> <span class="s2">&#34;#FFFFFF&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;white&#34;</span><span class="p">:</span> <span class="s2">&#34;#F8DCC0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;yellow&#34;</span><span class="p">:</span> <span class="s2">&#34;#E7741E&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;showTabsInTitlebar&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;tabWidthMode&#34;</span><span class="p">:</span> <span class="s2">&#34;titleLength&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;theme&#34;</span><span class="p">:</span> <span class="s2">&#34;dark&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;windowingBehavior&#34;</span><span class="p">:</span> <span class="s2">&#34;useAnyExisting&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script>]]></content:encoded>
    </item>
    <item>
      <title>Markov Junior</title>
      <link>https://aikenh.cn/posts/markovjunior/</link>
      <pubDate>Sun, 10 Jul 2022 11:26:00 +0000</pubDate>
      <guid>https://aikenh.cn/posts/markovjunior/</guid>
      <description>概率编程语言Markov Junior 随机生成迷宫</description>
      <content:encoded><![CDATA[<p>@Reference: <a href="https://mp.weixin.qq.com/s?__biz=MzIxODg1OTk1MA==&amp;mid=2247513354&amp;idx=1&amp;sn=28b5492cc0a86b04f0a0b975bf42568c&amp;ascene=56&amp;devicetype=iOS15.5&amp;version=1800172f&amp;nettype=WIFI&amp;abtest_cookie=AAACAA%3D%3D&amp;lang=zh_CN&amp;fontScale=100&amp;exportkey=ARSr9kinLTM%2B6fr7WYBKF%2FM%3D&amp;pass_ticket=gK4kcTE5wfRRXzd0FMTJlg9zBNGh%2BZ5VoWQkUbqSJXykXGIdMXasyLJgUxII1IDt&amp;wx_header=3" target="_blank" rel="noopener">Jack Cui</a>
 | <a href="https://github.com/mxgmn/MarkovJunior" target="_blank" rel="noopener">Github-Markov Junior</a>
 | <a href="https://github.com/mxgmn/MarkovJunior" target="_blank" rel="noopener">Wiki Markov algorithm</a>
</p>
<p>第一篇文章简要介绍了一下该编程语言能实现什么效果；第二个是官方repo，其文档和代码都有很强的借鉴意义；第三个是wikipedia对马尔可夫算法的解释，在该编程语言的实现中有重要的意义。</p>
<h2 id="markov-algorithm">markov algorithm</h2>
<p>马尔可夫算法指的是字符串重写算法，其基本逻辑如下:</p>
<ol>
<li>自顶向下依次检查规则，看是否能在符号串中找到任何在箭头左边的字符串。</li>
<li>如果没有找到，停止执行算法。</li>
<li>如果找到一个或多个，把符号串中的最左匹配的文字替换为在第一个相应规则的箭头右边的字符串。</li>
<li>返回步骤1并继续。（如果应用的规则是终止规则，则停止执行算法。） [1]</li>
</ol>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220710134410108.png">
    <img alt="image-20220710134410108" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220710134410108.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/image-20220710134410108.png" style="display: block; margin: 0 auto;"
      alt="image-20220710134410108"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="markovjunior">MarkovJunior</h2>
<p>Markov Junior是一种基于概率的编程语言，通过重写和传播规则（约束）来实现随机的生成和编写。最终对画布进行重写来实现随机的生成。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://github.com/mxgmn/MarkovJunior/raw/main/images/top-iso.gif">
    <img alt="sample" loading="lazy" src="https://github.com/mxgmn/MarkovJunior/raw/main/images/top-iso.gif"class="responsive-image" src="https://github.com/mxgmn/MarkovJunior/raw/main/images/top-iso.gif" style="display: block; margin: 0 auto;"
      alt="sample"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>如上图所示，基础规则的约束以上图所示的<strong>色块变换</strong>和<strong>Pattern</strong>决定，再<strong>基于马尔可夫算法</strong>的规则，从上到下的规则逐渐进行<strong>转化和重写</strong>，实现最终关卡和规则的生成。</p>
<p>具体的例子如下，通过设定红色起点和颜色转换规则来进行全局的随机搜索实现色块的变化最后生成迷宫。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://github.com/mxgmn/MarkovJunior/raw/main/images/MazeBacktracker.gif">
    <img alt="MazeBackTracker" loading="lazy" src="https://github.com/mxgmn/MarkovJunior/raw/main/images/MazeBacktracker.gif"class="responsive-image" src="https://github.com/mxgmn/MarkovJunior/raw/main/images/MazeBacktracker.gif" style="display: block; margin: 0 auto;"
      alt="MazeBackTracker"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>最基本的规则如上图所示，更为复杂的规则和写法可以通过参考GIthub上面的样例并进行自我实现来学习一下。</p>
<h3 id="实现和测试">实现和测试</h3>
]]></content:encoded>
    </item>
    <item>
      <title>Wave Function Collapse</title>
      <link>https://aikenh.cn/posts/wfc%E7%AE%97%E6%B3%95/</link>
      <pubDate>Sun, 10 Jul 2022 09:42:50 +0000</pubDate>
      <guid>https://aikenh.cn/posts/wfc%E7%AE%97%E6%B3%95/</guid>
      <description>对波函数坍塌算法的理解</description>
      <content:encoded><![CDATA[<p>@Reference: <a href="https://github.com/mxgmn/WaveFunctionCollapse" target="_blank" rel="noopener">Github-Mxgmn</a>
 | <a href="https://zhuanlan.zhihu.com/p/66416593" target="_blank" rel="noopener">zhihu</a>
</p>
<h2 id="概念简介和复习">概念简介和复习</h2>
<p>本质上该方法的底层思想就是条件概率的启发式随机生成算法。</p>
<h3 id="波函数坍塌">波函数坍塌</h3>
<p>在介绍算法之前首先需要明确几个概念，第一个就是**“波函数坍塌”<strong>（名字的来源是量子力学中的概念），参考</strong>“薛定谔的猫”<strong>，可以理解成：在一系列的不确定像素（存在多种可能）的基础之上，通过</strong>确定的规则**、<strong>相关关系</strong>，随机的将所有的像素变成确定的状态。（可以通过给定种子来启动，也可以通过随机规则来启动），实现在一定规则或者模式下的随机生成。</p>
<h3 id="熵">熵</h3>
<p><strong>熵</strong>作为热力学中，表示物理状态的参量，其含义在于表示物质的<strong>混乱程度</strong>（正相关）。在当前的场景下，使用信息熵（而非热熵）来衡量变量的<strong>不确定程度</strong>（完全随机，或者有限随机，或者二选一等等）。</p>
<div>
$$ 
H(X) = \sum_{x\in X}p(x)log p(x)
 $$
</div>
<p>式中描述的是信息熵的计算公式，在实际应用中，可以使用任何表示状态不确定程度的度量来进行一下的计算。</p>
<h2 id="算法原理-流程">算法原理-流程</h2>
<p>动态地使可选的范围越来越小，直到最后整体都是确定的状态。而缩小范围的方法核心可以总结为（数独）：</p>
<ul>
<li>
<p><strong>约束规则</strong>、<strong>状态传播</strong>、<strong>回溯</strong></p>
</li>
<li>
<p>从最小熵的单位开始坍缩，保证最小概率的坍缩失败，从而<strong>减少大量的回溯</strong>过程，来减少计算量。</p>
</li>
</ul>
<p>以<strong>地图生成</strong>为例：</p>
<p><strong>约束规则</strong>：（选择一个熵最小的slot开始）针对于每个slot的坍缩，是在ModuleSet（可选模块集合）中随机取一个概率最高的模块，进行合成，而这个概率受我们制定的<strong>规则</strong>，<strong>周边的Slot</strong>的状态影响。
<strong>状态传播</strong>：模块确定后就将该状态和规则传递到相邻的moduleset中，删除不匹配的模块等。
<strong>回溯</strong>：当坍缩陷入矛盾（与规则相互矛盾，坍缩失效），就对状态进行回溯（Backtrack）重新进行状态搜索和回溯。</p>
<blockquote>
<ol>
<li>Read the input bitmap and count NxN patterns.
<ol>
<li>(optional) Augment pattern data with rotations and reflections.</li>
</ol>
</li>
<li>Create an array with the dimensions of the output (called &ldquo;wave&rdquo; in the source). Each element of this array represents a state of an NxN region in the output. A state of an NxN region is a superposition of NxN patterns of the input with boolean coefficients (so a state of a pixel in the output is a superposition of input colors with real coefficients). False coefficient means that the corresponding pattern is forbidden, true coefficient means that the corresponding pattern is not yet forbidden.</li>
<li>Initialize the wave in the completely unobserved state, i.e. with all the boolean coefficients being true.</li>
<li>Repeat the following steps:
<ol>
<li>Observation:
<ol>
<li>Find a wave element with the minimal nonzero entropy. If there is no such elements (if all elements have zero or undefined entropy) then break the cycle (4) and go to step (5).</li>
<li>Collapse this element into a definite state according to its coefficients and the distribution of NxN patterns in the input.</li>
</ol>
</li>
<li>Propagation: propagate information gained on the previous observation step.</li>
</ol>
</li>
<li>By now all the wave elements are either in a completely observed state (all the coefficients except one being zero) or in the contradictory state (all the coefficients being zero). In the first case return the output. In the second case finish the work without returning anything.</li>
</ol>
</blockquote>
<h2 id="code">Code</h2>
<p>官方仓库中有诸多样例和各种代码版本的实现，可以参考并实现部分版本。</p>
<h3 id="样例解读">样例解读</h3>
<h3 id="样例实现">样例实现</h3>
]]></content:encoded>
    </item>
    <item>
      <title>Z Jumper for Linux</title>
      <link>https://aikenh.cn/posts/z_jumper/</link>
      <pubDate>Fri, 20 May 2022 21:22:53 +0000</pubDate>
      <guid>https://aikenh.cn/posts/z_jumper/</guid>
      <description>Reduce &amp;#39;cd&amp;#39; to facilitate jumping between projects</description>
      <content:encoded><![CDATA[<p>Star this <a href="https://github.com/rupa/z" target="_blank" rel="noopener">Project</a>
 in Github after u decide to use it.</p>
<h2 id="download--install">Download &amp; Install</h2>
<p><strong>Firstly</strong>, Cpy <code>z.sh</code> to the path u want make this script can be <strong>recognizabled by your shell</strong> like zsh, bash.</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nb">cd</span> ~
</span></span><span class="line"><span class="cl">wget https://raw.githubusercontent.com/rupa/z/master/z.sh</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>Secondly</strong>, add <code>. ~/z.sh</code>  to the end of your <code>.zshrc</code> ，u can use following cmd also</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;. ~/z.sh&#34;</span> &gt;&gt; ~/.zshrc
</span></span><span class="line"><span class="cl"><span class="c1"># then using this to check </span>
</span></span><span class="line"><span class="cl">tail -n <span class="m">5</span> ~/.zshrc</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>Fi</strong>, activate it.</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nb">source</span> ~/.zshrc</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="usage-and-description">Usage and Description</h2>
<p>以以下的目录为例：<code>the/path/to/UniFramwork</code>，演示该jumper的使用方式。我们首先需要进入（<code>cd</code>）过对应的目录，<code>z</code>将会记录看，并计算相应的权重，通过其维护的List来进行快速跳转，在完成记录后，我们即可用下面跳转到项目文件夹：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">z uni
</span></span><span class="line"><span class="cl">z un
</span></span><span class="line"><span class="cl">.....</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>该Jumper的优势在于，<strong>可在任何目录进行跳转</strong>，ITs Good</p>
]]></content:encoded>
    </item>
    <item>
      <title>设置各Editor自动添加meta信息</title>
      <link>https://aikenh.cn/posts/hexo_write/</link>
      <pubDate>Wed, 13 Apr 2022 23:29:10 +0000</pubDate>
      <guid>https://aikenh.cn/posts/hexo_write/</guid>
      <description>设置 vscode, vim, obsidian 自动为 Markdown 添加 Hexo 所需Meta信息</description>
      <content:encoded><![CDATA[<p>Hexo和Gitee一致，都是由Markdown文件为基础，构建的博客，编写Markdown本身无需多言，由于Hexo并非笔者的首选笔记管理方式，故而再其他地方构建和编写文件是常态，该Blog主要是利用其他工具来方便Hexo博文的编写（Header）</p>
<p>默认的是 <code>hexo new [layout] title</code> 可简写为 <code>hexo n [layout] title</code>，其中布局应该是在博客目录中定义，该命令也局限于博客的对应目录。</p>
<blockquote>
<p>post(默认)、draft、page</p>
</blockquote>
<p>除了默认的方法，本篇将介绍Obsidian、VsCode-like、Vim自动添加Header的方式，用以方便随时随地的编写博文。</p>
<p>同时为了方便已有笔记迁移，本文也编写了Python脚本，CPY后为Target Dir的版本自动添加Header，但是其中对应的Catagories最好还是手动修改一下。</p>
<h2 id="obsidian">Obsidian</h2>
<p>通过<strong>template</strong>插件，按照对应主题的Header样式添加，可以去官方文档中找对应的语法和说明。从而构建自己的Template</p>
<p><strong>Workflow</strong>：插件市场添加Template -&gt; 设置指定Template文件夹 -&gt; 按照语法编写Template文件 -&gt; 使用快捷键插入模板</p>
<p>由于这一块没有什么存在歧义的操作，就不赘述，唯一需要注意的是语法，简单参考一下<a href="https://silentvoid13.github.io/Templater/" target="_blank" rel="noopener">官方的Example</a>
即可，无需过于深入</p>
<p>本文使用的是Live my Life的Hexo-Theme，模板文件如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ts</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="o">---</span>
</span></span><span class="line"><span class="cl"><span class="nx">title</span><span class="o">:</span> <span class="o">&lt;%</span> <span class="nx">tp</span><span class="p">.</span><span class="nx">file</span><span class="p">.</span><span class="nx">title</span> <span class="o">%&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nx">catalog</span>: <span class="kt">true</span>
</span></span><span class="line"><span class="cl"><span class="nx">data</span><span class="o">:</span> <span class="o">&lt;%</span> <span class="nx">tp</span><span class="p">.</span><span class="nx">date</span><span class="p">.</span><span class="nx">now</span><span class="p">(</span><span class="s2">&#34;YYYY-MM-DD HH:mm:ss&#34;</span><span class="p">)</span> <span class="o">%&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nx">subtitle</span>:
</span></span><span class="line"><span class="cl"><span class="kt">lang</span><span class="o">:</span> <span class="nx">cn</span>
</span></span><span class="line"><span class="cl"><span class="nx">header</span><span class="o">-</span><span class="nx">img</span><span class="o">:</span> <span class="err">/img/header_img/lml_bg1.jpg</span>
</span></span><span class="line"><span class="cl"><span class="nx">tag</span><span class="o">:</span>
</span></span><span class="line"><span class="cl"><span class="o">-</span> 
</span></span><span class="line"><span class="cl"><span class="nx">categories</span><span class="o">:</span>
</span></span><span class="line"><span class="cl"><span class="o">-</span>
</span></span><span class="line"><span class="cl"><span class="nx">mathjax</span>: <span class="kt">true</span>
</span></span><span class="line"><span class="cl"><span class="nx">sticky</span>: <span class="kt">22</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">---</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>实际上各个模块的操作思想都是一致的Snippet方案。</p>
<h2 id="vimnvim">Vim/Nvim</h2>
<p>通过Vimscript设置或者Lua的设置文件，令Vim，Neovim再新建<code>.md</code>的同时，为其添加默认Header。Lua实际上调用的是Vimscript的接口，这里仅给出<code>.lua</code>版本，相应的转换不在赘言。</p>
<p>配置NeoVim中的 <code>~/.config/nvim/lua/basic/config.lua</code></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>lua</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="cl"><span class="n">vim.cmd</span><span class="p">(</span><span class="s1">&#39;autocmd BufNewFile *.md,*.sh,*.cpp,*.py,*.lua exec &#34;:lua set_title()&#34;&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="kr">function</span> <span class="nf">set_title</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">filetype</span> <span class="o">=</span> <span class="n">vim.fn</span><span class="p">.</span><span class="n">expand</span><span class="p">(</span><span class="s2">&#34;%:e&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1">-- set title for markdown</span>
</span></span><span class="line"><span class="cl">    <span class="kr">if</span> <span class="n">filetype</span> <span class="o">==</span> <span class="s2">&#34;md&#34;</span> <span class="kr">then</span>
</span></span><span class="line"><span class="cl">		<span class="n">vim.fn</span><span class="p">.</span><span class="n">setline</span><span class="p">(</span><span class="s2">&#34;1&#34;</span><span class="p">,</span> <span class="s2">&#34;--- &#34;</span> <span class="o">..</span> <span class="n">vim.fn</span><span class="p">.</span><span class="n">expand</span><span class="p">(</span><span class="s2">&#34;%&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="n">vim.fn</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">vim.fn</span><span class="p">.</span><span class="n">line</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">),</span> <span class="s2">&#34;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">vim.fn</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">vim.fn</span><span class="p">.</span><span class="n">line</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">)</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="s2">&#34;Author: AikenHong  &#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">vim.fn</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">vim.fn</span><span class="p">.</span><span class="n">line</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">)</span><span class="o">+</span><span class="mi">2</span><span class="p">,</span> <span class="s2">&#34;Mail: h.aiken.970@gmail.com  &#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">vim.fn</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">vim.fn</span><span class="p">.</span><span class="n">line</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">)</span><span class="o">+</span><span class="mi">3</span><span class="p">,</span> <span class="s2">&#34;Date: &#34;</span> <span class="o">..</span> <span class="n">os.date</span><span class="p">(</span><span class="s2">&#34;%Y-%m-%d %H:%M:%S  &#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="n">vim.fn</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">vim.fn</span><span class="p">.</span><span class="n">line</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">)</span><span class="o">+</span><span class="mi">4</span><span class="p">,</span> <span class="s2">&#34;Desc: &#34;</span><span class="p">)](</span><span class="o">&lt;</span><span class="n">vim.fn</span><span class="p">.</span><span class="n">setline</span><span class="p">(</span><span class="s2">&#34;1&#34;</span><span class="p">,</span> <span class="s2">&#34;---&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">vim.fn</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">vim.fn</span><span class="p">.</span><span class="n">line</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">),</span> <span class="s2">&#34;title: &#34;</span> <span class="o">..</span> <span class="n">vim.fn</span><span class="p">.</span><span class="n">expand</span><span class="p">(</span><span class="s2">&#34;%&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="n">vim.fn</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">vim.fn</span><span class="p">.</span><span class="n">line</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">)</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="s2">&#34;catalog: true&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">vim.fn</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">vim.fn</span><span class="p">.</span><span class="n">line</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">)</span><span class="o">+</span><span class="mi">2</span><span class="p">,</span> <span class="s2">&#34;subtitle: &#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">vim.fn</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">vim.fn</span><span class="p">.</span><span class="n">line</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">)</span><span class="o">+</span><span class="mi">3</span><span class="p">,</span> <span class="s2">&#34;date: &#34;</span> <span class="o">..</span> <span class="n">os.date</span><span class="p">(</span><span class="s2">&#34;%Y-%m-%d %H:%M:%S  &#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="n">vim.fn</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">vim.fn</span><span class="p">.</span><span class="n">line</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">)</span><span class="o">+</span><span class="mi">4</span><span class="p">,</span> <span class="s2">&#34;lang: cn&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">vim.fn</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">vim.fn</span><span class="p">.</span><span class="n">line</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">)</span><span class="o">+</span><span class="mi">5</span><span class="p">,</span> <span class="s2">&#34;header-img: /img/header_img/lml_bg1.jpg&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">vim.fn</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">vim.fn</span><span class="p">.</span><span class="n">line</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">)</span><span class="o">+</span><span class="mi">6</span><span class="p">,</span> <span class="s2">&#34;tag: &#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">vim.fn</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">vim.fn</span><span class="p">.</span><span class="n">line</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">)</span><span class="o">+</span><span class="mi">7</span><span class="p">,</span> <span class="s2">&#34;-  &#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">vim.fn</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">vim.fn</span><span class="p">.</span><span class="n">line</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">)</span><span class="o">+</span><span class="mi">8</span><span class="p">,</span> <span class="s2">&#34;categories: &#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">vim.fn</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">vim.fn</span><span class="p">.</span><span class="n">line</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">)</span><span class="o">+</span><span class="mi">9</span><span class="p">,</span> <span class="s2">&#34;-  &#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">vim.fn</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">vim.fn</span><span class="p">.</span><span class="n">line</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">)</span><span class="o">+</span><span class="mi">10</span><span class="p">,</span> <span class="s2">&#34;mathjax: true&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">vim.fn</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">vim.fn</span><span class="p">.</span><span class="n">line</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">)</span><span class="o">+</span><span class="mi">11</span><span class="p">,</span> <span class="s2">&#34;sticky: &#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">vim.fn</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">vim.fn</span><span class="p">.</span><span class="n">line</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">)</span><span class="o">+</span><span class="mi">12</span><span class="p">,</span> <span class="s2">&#34;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">vim.fn</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">vim.fn</span><span class="p">.</span><span class="n">line</span><span class="p">(</span><span class="s2">&#34;.&#34;</span><span class="p">)</span><span class="o">+</span><span class="mi">13</span><span class="p">,</span> <span class="s2">&#34;---&#34;</span><span class="p">)</span><span class="o">&gt;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="kr">end</span>
</span></span><span class="line"><span class="cl"><span class="kr">end</span>        </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这样当我们用<code>nvim newblog.md</code>的时候，会自动添加上Header。</p>
<h2 id="vscode">Vscode</h2>
<p>使用Snippet插件添加代码片段，等待补充。</p>
<h2 id="convert-md2blogs">Convert md2Blogs</h2>
<p>使用Python脚本为原有<code>.md</code> 批量添加Header，缺点是不太灵活，但是用于初始化还是能省不少事。如果原本按照Tag，或者Categories进行文件夹归类的话，倒是能起到不错的初始化效果。</p>
<p>Shut Out and Show my <strong>Code</strong>：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># define the path of saving and the target path.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Specific for windows or Linux version yourself</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_all_blogs</span><span class="p">(</span><span class="n">path</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># get all blog path.</span>
</span></span><span class="line"><span class="cl">    <span class="n">dirs</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="n">BlogPath</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">blogs</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">blog_dir</span> <span class="ow">in</span> <span class="n">dirs</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">blog_dir</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s1">&#39;.obsidian&#39;</span><span class="p">,</span><span class="s1">&#39;_book&#39;</span><span class="p">,</span> <span class="s1">&#39;Day Planners&#39;</span><span class="p">,</span> <span class="s1">&#39;node_module&#39;</span><span class="p">,</span><span class="s1">&#39;Draft&#39;</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl">            <span class="n">tmpdir</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">BlogPath</span><span class="p">,</span> <span class="n">blog_dir</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">blogs</span> <span class="o">+=</span> <span class="n">glob</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="n">tmpdir</span> <span class="o">+</span> <span class="s1">&#39;/*.md&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># del using _ replace space of filename.</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">blog</span> <span class="ow">in</span> <span class="n">blogs</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="s1">&#39; &#39;</span> <span class="ow">in</span> <span class="n">blog</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">blog</span> <span class="o">=</span> <span class="n">blog</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39; &#39;</span><span class="p">,</span> <span class="s1">&#39;_&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="nb">print</span><span class="p">(</span><span class="n">blog</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">blogs</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>获取文件后我们需要得到文件的一些基本属性，用于Header中对应值的填充</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># TODO: get the basic info of each blog</span>
</span></span><span class="line"><span class="cl"><span class="c1"># title(name of files) \ catalog: true \ data: create time \ subtitle: desc \ lang cn\en</span>
</span></span><span class="line"><span class="cl"><span class="c1"># header-img: we can create a loop to generate this part.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># tags, categories, mathjax.</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">change_realtime</span><span class="p">(</span><span class="n">timestamp</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">time_struct</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">localtime</span><span class="p">(</span><span class="n">timestamp</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">time</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s1">&#39;%Y-%m-</span><span class="si">%d</span><span class="s1"> %H:%M:%S&#39;</span><span class="p">,</span> <span class="n">time_struct</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_attribute</span><span class="p">(</span><span class="n">blog</span><span class="p">,</span> <span class="n">verbose</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">attr</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># get timestamp.</span>
</span></span><span class="line"><span class="cl">    <span class="n">create_time</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">getctime</span><span class="p">(</span><span class="n">blog</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">modify_time</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">getmtime</span><span class="p">(</span><span class="n">blog</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">attr</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">change_realtime</span><span class="p">(</span><span class="n">create_time</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">attr</span><span class="p">[</span><span class="s1">&#39;m_data&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">change_realtime</span><span class="p">(</span><span class="n">modify_time</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># get tags and categories.</span>
</span></span><span class="line"><span class="cl">    <span class="n">tags</span> <span class="o">=</span> <span class="n">blog</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;</span><span class="se">\\</span><span class="s1">&#39;</span><span class="p">)[</span><span class="o">-</span><span class="mi">2</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">attr</span><span class="p">[</span><span class="s1">&#39;tags&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">tags</span>
</span></span><span class="line"><span class="cl">    <span class="n">attr</span><span class="p">[</span><span class="s1">&#39;categories&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">tags</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># get title.</span>
</span></span><span class="line"><span class="cl">    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">blog</span><span class="p">,</span> <span class="s1">&#39;r&#39;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s1">&#39;UTF-8&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">lines</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="n">title</span> <span class="o">=</span> <span class="n">lines</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;#&#39;</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="n">attr</span><span class="p">[</span><span class="s1">&#39;title&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">title</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># default attr</span>
</span></span><span class="line"><span class="cl">    <span class="n">attr</span><span class="p">[</span><span class="s1">&#39;lang&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;cn&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># verbose:</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">verbose</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="n">blog</span><span class="p">,</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">,</span> <span class="n">attr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">attr</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>为了不意外损坏源文件，同时保持源文件的结构、组织和属性等等，我们Cpy并只对副本进行操作，cpy的同时转移文件路径到所需地点。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">cpy_files</span><span class="p">(</span><span class="n">blog</span><span class="p">,</span><span class="n">target</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;cpy files to the target path&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">filename</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">blog</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">os</span><span class="o">.</span><span class="n">system</span><span class="p">(</span><span class="s1">&#39;cp &#39;</span> <span class="o">+</span> <span class="n">blog</span> <span class="o">+</span> <span class="s1">&#39; &#39;</span> <span class="o">+</span> <span class="n">target</span> <span class="o">+</span> <span class="n">filename</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">target</span> <span class="o">+</span> <span class="n">filename</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在获取完基本属性和转移后，我们需要开始对文件进行添加header的处理,在这里我们添加了一个Loop为Blog设置不同的背景图片，根据自己有多少图片进行自定义设置吧。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">add_header</span><span class="p">(</span><span class="n">blog</span><span class="p">,</span><span class="n">index</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span><span class="n">attr</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;add default header for each files&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">header_imgs</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;&#34;</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">blog</span><span class="p">,</span> <span class="s2">&#34;r+&#34;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s1">&#39;UTF-8&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">old</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="n">f</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&#34;---</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&#34;title: &#34;</span> <span class="o">+</span> <span class="n">attr</span><span class="p">[</span><span class="s1">&#39;title&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&#34;</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&#34;catalog: true</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&#34;date: &#34;</span> <span class="o">+</span> <span class="n">attr</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&#34;</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&#34;subtitle: </span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&#34;lang: &#34;</span> <span class="o">+</span> <span class="n">attr</span><span class="p">[</span><span class="s1">&#39;lang&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&#34;</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&#34;header-img: &#34;</span> <span class="o">+</span> <span class="s1">&#39;/img/header_img/lml_bg</span><span class="si">{}</span><span class="s1">.jpg&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">index</span><span class="o">%</span><span class="mi">6</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&#34;</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&#34;tags: &#34;</span> <span class="o">+</span> <span class="s2">&#34;</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&#34;-  &#34;</span> <span class="o">+</span> <span class="n">attr</span><span class="p">[</span><span class="s1">&#39;tags&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&#34;</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&#34;categories: &#34;</span> <span class="o">+</span> <span class="s2">&#34;</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&#34;-  &#34;</span> <span class="o">+</span> <span class="n">attr</span><span class="p">[</span><span class="s1">&#39;categories&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&#34;</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&#34;---</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">old</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>然后就是执行文件夹的批量处理了。可以添加args便于对多个文件夹进行处理，或者控制只变换单个文件等，应该需求不大，且代码比较简单，这里就暂时不贴出了。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">dir_process</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">blogs</span> <span class="o">=</span> <span class="n">get_all_blogs</span><span class="p">(</span><span class="n">BlogPath</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">i</span><span class="p">,</span><span class="n">blog</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">blogs</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">b_attr</span> <span class="o">=</span> <span class="n">get_attribute</span><span class="p">(</span><span class="n">blog</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">new_blog</span> <span class="o">=</span> <span class="n">cpy_files</span><span class="p">(</span><span class="n">blog</span><span class="p">,</span> <span class="n">TargetPath</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">add_header</span><span class="p">(</span><span class="n">new_blog</span><span class="p">,</span> <span class="n">index</span><span class="o">=</span><span class="n">i</span><span class="p">,</span> <span class="n">attr</span><span class="o">=</span><span class="n">b_attr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">dir_process</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Done!&#39;</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script>]]></content:encoded>
    </item>
    <item>
      <title>Latex tesing</title>
      <link>https://aikenh.cn/posts/latex_testing/</link>
      <pubDate>Wed, 13 Apr 2022 16:50:53 +0000</pubDate>
      <guid>https://aikenh.cn/posts/latex_testing/</guid>
      <description>test hexo render</description>
      <content:encoded><![CDATA[<p>该文档主要目的是用于测试Latex语法对应前端的渲染能力，主要用于测试Hexo站点是否能正常渲染Latex。</p>
<p>Example1: 2 inline in one sentence.</p>
<p>When $a \ne 0$ , there are two solutions to $(ax^2 + bx + c = 0)$ and they are</p>
<div>
$$ x = {-b \pm \sqrt{b^2-4ac} \over 2a}. $$
</div>
<p>Example2: Matrix Example</p>
<div>
$$ 
\begin{bmatrix} 1&x&x^2\\ 1&y&y^2\\ 1&z&z^2 \end{bmatrix}
\\
\begin{bmatrix} 1&x&x^2\\\\ 1&y&y^2\\\\ 1&z&z^2 \end{bmatrix}
\\
vmatrix ||、Bmatrix{}、pmatrix()
 $$
</div>
<p>Example3: the Conditional Formula</p>
<div>
$$ 
f(x)=
\begin{cases}
0& \text{x=0}\\\\
1& \text{x!=0}
\end{cases}
 $$
</div>
<p>Example4: Sprcial Symboy</p>
<div>
$$ 
\lim_{\alpha \rightarrow +\infty} \frac{1}{\alpha(\beta+1)}
 $$
</div>
<p>Example5: Complex Function Which Occurs Error in Much Situation</p>
<div>
$$ 
\begin{gathered}
\mathcal{L}_{POD-final} = \frac{\lambda_c}{L-1}\sum_{l=1}^{L-1} \mathcal{L}_{POD-spatial}(f_l^{t-1}(x),f_l^t(x)) +  \\
\lambda_f \mathcal{L}_{POD-flat}(f_l^{t-1}(x),f_l^t(x))
\end{gathered}
 $$
</div>
<p>Example6：Mathbb、Text、etc&hellip;</p>
<div>
$$ 
\mathcal{L}_{\text {POD-pixel }}\left(\mathbf{h}_{\ell}^{t-1}, \mathbf{h}_{\ell}^{t}\right)=\sum_{c=1}^{C} \sum_{w=1}^{W} \sum_{h=1}^{H}\left\|\mathbf{h}_{\ell, c, w, h}^{t-1}-\mathbf{h}_{\ell, c, w, h}^{t}\right\|^{2}
 $$
</div>
<p>Example7: Multiple Lines of Loss in Incremental Learning</p>
<div>
$$ 
\begin{gathered}
\mathcal{L}_{\text {POD-channel }}\left(\mathbf{h}_{\ell}^{t-1}, \mathbf{h}_{\ell}^{t}\right)=\sum_{w=1}^{W} \sum_{h=1}^{H}\left\|\sum_{c=1}^{C} \mathbf{h}_{\ell, c, w, h}^{t-1}-\sum_{c=1}^{C} \mathbf{h}_{\ell, c, w, h}^{t}\right\|^{2} \\
\mathcal{L}_{\text {POD-gap }}\left(\mathbf{h}_{\ell}^{t-1}, \mathbf{h}_{\ell}^{t}\right)=\sum_{c=1}^{C}\left\|\sum_{w=1}^{W} \sum_{h=1}^{H} \mathbf{h}_{\ell, c, w, h}^{t-1}-\sum_{w=1}^{W} \sum_{h=1}^{H} \mathbf{h}_{\ell, c, w, h}^{t}\right\|^{2} \\
\mathcal{L}_{\text {POD-width }}\left(\mathbf{h}_{\ell}^{t-1}, \mathbf{h}_{\ell}^{t}\right)=\sum_{c=1}^{C} \sum_{h=1}^{H}\left\|\sum_{w=1}^{W} \mathbf{h}_{\ell, c, w, h}^{t-1}-\sum_{w=1}^{W} \mathbf{h}_{\ell, c, w, h}^{t}\right\|^{2}
\end{gathered}
 $$
</div>
<p>如果这些都能正确渲染的话，基本整个文档中的Latex基本渲染应该都没问题，用该文档能验证当前本地渲染的版本是否是正确的。</p>
]]></content:encoded>
    </item>
    <item>
      <title>部署和发布 Hexo 博客</title>
      <link>https://aikenh.cn/posts/hexo_build/</link>
      <pubDate>Tue, 12 Apr 2022 11:16:30 +0000</pubDate>
      <guid>https://aikenh.cn/posts/hexo_build/</guid>
      <description>以 Livemylive 为例搭建并发布自己的Hexo博客</description>
      <content:encoded><![CDATA[<p>该文档用以，记录自己（外行）利用Hexo建立Blog的过程，将原本用Gitbook构建的笔记转移到Hexo中，同时购买域名并部署其上。网页部署于<a href="AikenH.cn">Github Page</a>
。以Live my Live主题为例。</p>
<p>腾讯云和Github Page的操作和理解在现有的一些博客中过时了，或者说存在一些问题，后续会对此进行简单的讲解。同时大部分博客都是使用NexT主题进行配置，这里采用的是Live My Life主题，该博文介绍自己的粗浅理解，也为自己后续的工作进行一定的参考。</p>
<p>还存在一些<strong>没有解决</strong>的问题：</p>
<ul>
<li>对主题切换和主题配置和全局配置的的深入理解（Live my Life主题覆盖了很多默认配置）</li>
<li>前端代码的理解，<strong>自定义Layout</strong>，超链接，图标等</li>
<li>深入理解插件的应用和自定义</li>
<li>推送网站到baidu和google（Option）（没有计划）</li>
</ul>
<p>之后有时间的话可以去研究一下：</p>
<p><strong>关键词</strong>：Hexo_Livemylive、Github Page、腾讯云（Domain、DNS、SSL）</p>
<h2 id="environment">Environment</h2>
<p>需要准备的环境如下：本地Node（NPM），Page部署Git（SSH），可在Windows，Linux，WSL2中部署均可，但需要注意的是，如果在WSL2中进行部署，生成速度与部署速度会明显慢于宿主机。</p>
<p>首先安装NodeJS、NPM、Git并验证是否成功安装，根据Linux和Windows不同环境进行安装，可以去官网了解相关的安装步骤，或者参考Gitee和Github的两篇博文。</p>
<p>为了更好的编写笔记，最好配置一个图床，图床的配置可以使用Github、Gitee或者腾讯云的COS服务，相关的配置可以参考<a href="https://aikenh.cn/en/PicBed/" target="_blank" rel="noopener">LInk</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sh</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">git version
</span></span><span class="line"><span class="cl">node -v
</span></span><span class="line"><span class="cl">npm -v</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>安装Hexo</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sh</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">npm install -g hexo-cli
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 查看Hexo的版本</span>
</span></span><span class="line"><span class="cl">hexo -v</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="initialize">Initialize</h2>
<h3 id="blog">Blog</h3>
<p>对博客目录初始化：<code>hexo init blog</code>，blog为空的话初始化当前文件夹，初始化后基本结构如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sh</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">.
</span></span><span class="line"><span class="cl">├── _config.yml <span class="c1"># 网站的全局配置信息，在此配置大部分的参数。 </span>
</span></span><span class="line"><span class="cl">├── package.json <span class="c1"># 定义Hexo，以及对应安装的依赖的版本等</span>
</span></span><span class="line"><span class="cl">├── node_module: <span class="c1"># Hexo安装插件的位置</span>
</span></span><span class="line"><span class="cl">├── scaffolds <span class="c1"># 页面模版文件夹</span>
</span></span><span class="line"><span class="cl">├── <span class="nb">source</span>  <span class="c1"># 资源文件夹，除 _posts 文件，其他以下划线_开头的文件或者文件夹不会被编译打包到public文件夹</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span>   ├── _drafts <span class="c1"># 草稿文件</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span>   └── _posts <span class="c1"># 文章Markdowm文件 </span>
</span></span><span class="line"><span class="cl">└── themes  <span class="c1"># 主题文件夹</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>有了初始化的目录后，就可以参考相关主题的官方介绍页面进行对应的 配置，不同的主题可能有不同的配置方法。接下来我们会以<a href="https://github.com/V-Vincen/hexo-theme-livemylife/blob/master/README_CN.md" target="_blank" rel="noopener">《Live my life》</a>
主题为例。</p>
<p>后续基于别的主题对文件配置有了更深入的理解后，会对配置部分进行更新说明，或另开一贴。</p>
<h3 id="github">Github</h3>
<p>本文使用Github Page构建自己的静态站点，用于部署自己的网页。GitHub只能使用一个同名仓库托管一个静态站点：aikenh.github.io，但是可以在此站之上，使用其他仓库构建子域名如: aikenh.github.io/Docs</p>
<p>Git和Github仓库和链接的初始化参见<a href="https://aikenh.cn/en/GitGithub/" target="_blank" rel="noopener">GitWorkflow</a>
；对应的io，可以通过建立【UserName】.github.io为名的Repo，并在<strong>Setting</strong>-&gt; <strong>Code and automation</strong> -&gt; <strong>Page</strong>中选择对应的Branch作为Source.</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220413001718.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220413001718.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220413001718.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>完成后如图所示，后续设置好域名解析服务后后可在<strong>Custom domain</strong>中设置你的自定义域名，github.io将自动转换成该域名，会在域名解析部分详细介绍</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220413001932.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220413001932.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220413001932.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>创建完该网站Github的初始部分差不多完成。</p>
<h2 id="config-livemylife">Config-livemylife</h2>
<p>本章节的基本操作均针对<code>_config.yml</code>进行。</p>
<p>基于我的理解，为了便于多主题的配置和切换，在主<em>Config.yml</em> 中应该尽量不参与特定主题的设置，而在<code>Theme/SpecificTheme/_config.yml</code>中为每个主题定制基本的配置为好。但目前只用过这个主题，就以此为例。</p>
<p>更多的设置去主题的readme中查看和设置。</p>
<p><strong>初始化主题</strong>：设置主题的基本需求，并基于此安装相关依赖</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sh</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="nb">cd</span> blog
</span></span><span class="line"><span class="cl">rm -rf scaffolds <span class="nb">source</span> themes _config.landscape.yml _config.yml package.json yarn.lock <span class="c1">#just keep node_modules</span>
</span></span><span class="line"><span class="cl">git clone https://github.com/V-Vincen/hexo-theme-livemylife.git
</span></span><span class="line"><span class="cl">mv hexo-theme-livemylife/* ./
</span></span><span class="line"><span class="cl">rm -rf hexo-theme-livemylife
</span></span><span class="line"><span class="cl">npm install</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>设置主题</strong>：修改配置中的theme值</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">theme</span><span class="p">:</span><span class="w"> </span><span class="l">livemylife</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">themecolor</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nt">enable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nt">mode</span><span class="p">:</span><span class="w"> </span><span class="l">light</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>完成了基础设置后，可以直接在本地运行博客，查看效果，方便后续调试后部署，具体命令如下</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">hexo cl <span class="o">&amp;&amp;</span> hexo g <span class="o">&amp;&amp;</span> hexo s -p your-port
</span></span><span class="line"><span class="cl"><span class="c1"># default port is 4000</span>
</span></span><span class="line"><span class="cl">hexo g <span class="o">&amp;&amp;</span> hexo s</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="basic-configs">Basic Configs</h3>
<p>使用自己的信息修改配置文件的对应选项，以下介绍一些基本属性配置：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="c"># header</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">title</span><span class="p">:</span><span class="w"> </span><span class="l">My_Blog</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">subtitle</span><span class="p">:</span><span class="w"> </span><span class="l">some description of u or ur site</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">author</span><span class="p">:</span><span class="w"> </span><span class="l">NickName</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">timezone</span><span class="p">:</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c"># url</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">url: http://aikenh.cn # note</span><span class="p">:</span><span class="w"> </span><span class="l">不要忘了修改source文件中的CNAME</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">root</span><span class="p">:</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">permalink</span><span class="p">:</span><span class="w"> </span><span class="p">:</span><span class="l">lang/:title/</span><span class="w"> </span><span class="c"># 子页面的链接形式</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c"># site setting</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">SEOTitle</span><span class="p">:</span><span class="w"> </span><span class="l">Names Blog</span><span class="w"> </span><span class="c"># 标签栏显示的标题</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="l">email：</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">description</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Development Documentation&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">keyword</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;name,Name,blog,Blog&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">header-img</span><span class="p">:</span><span class="w"> </span><span class="l">img/header_img/bg_img.jpg</span><span class="w"> </span><span class="c"># 标题图像的存储路径，Source为根路径</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">favicon</span><span class="p">:</span><span class="w"> </span><span class="l">img/avatar/f_img.png</span><span class="w"> </span><span class="c"># 标签栏显示的图像</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c"># 暂时不使用签名</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">signature</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">signature-img</span><span class="p">:</span><span class="w"> </span><span class="l">_ </span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>不使用<a href="https://v-vincen.life/en/How-to-Use-Internationalization%EF%BC%88i18n%EF%BC%89/" target="_blank" rel="noopener">Internationalization</a>
设置，关掉选项：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">langselect</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nt">enable</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>该选项会关闭生成语言选择按钮。</p>
<h3 id="effects-custom">Effects custom</h3>
<p>该部分控制页面的特效设置。主要包括关闭线段背景，线段背景消耗CPU的同时还会遮挡文字，故而关闭；鼠标点击特效mouseclick关闭，在界面使用的时候异常选中的问题以及遮挡的问题。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">wave</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c"># false can not disable this, should del content and color alse</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">mouseclick</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nt">enable</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nt">content</span><span class="p">:</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nt">color</span><span class="p">:</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">ribbonDynamic</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">bglinecanvas</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="sidebar--sns">Sidebar &amp; SNS</h3>
<p>启用侧边栏放置相关的个人信息，SNS的设置实际上也与该部分相关，会显示在头像的下方。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">sidebar</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">   </span><span class="c"># whether or not using Sidebar.</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">sidebar-about-description</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;making trash&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">sidebar-avatar</span><span class="p">:</span><span class="w"> </span><span class="l">img/avatar/samura.jpg   </span><span class="w"> </span><span class="c"># use absolute URL, seeing it&#39;s used in both `/` and `/about/`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">widgets</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="nt">visitor   # busuanzi</span><span class="p">:</span><span class="w"> </span><span class="l">https://busuanzi.ibruce.info/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="l">featured-tags</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="l">short-about</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="l">recent-posts</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="l">friends-blog</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="l">archive</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="l">category</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c"># widget behavior 设置相关的Archieve侧边部件</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c">## Archive</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">archive_type</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;monthly&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">show_count</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c">## Featured Tags </span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">featured-tags</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">   </span><span class="c"># whether or not using Feature-Tags</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">featured-condition-size</span><span class="p">:</span><span class="w"> </span><span class="m">0</span><span class="w">    </span><span class="c"># A tag will be featured if the size of it is more than this condition value</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c">## Friends 友站设置</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">friends</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>{<span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">title</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;GitBook&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">href</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;https://Name.github.io/Docs&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>}<span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>{<span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">title</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;Hexo&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">href</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;https://hexo.io/&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>}<span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c"># SNS Settings just enable what u want.</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">RSS</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">github_username</span><span class="p">:</span><span class="w"> </span><span class="l">yourAccount</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">twitter_username</span><span class="p">:</span><span class="w"> </span><span class="l">yourAccount</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c"># instagram_username: </span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c"># facebook_username:  yourAccount</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c"># linkedin_username:  yourAccount</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">zhihu_username</span><span class="p">:</span><span class="w"> </span><span class="l">yourAccount</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">weibo_username</span><span class="p">:</span><span class="w"> </span><span class="l">numid of weibo in url</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="layout-custom">Layout Custom</h3>
<p>修改一些页面布局，除了一些基础设置，还有还有一些对应的标签问题。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="c"># top scroll progress</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">scroll</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c"># make article sticky</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">top</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c"># count word for each doc</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">wordcount</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c"># show tag of each article</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">home_posts_tag</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c"># anchorjs 设置锚点</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">anchorjs</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">socialshare</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">viewer</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>页面的Newer Posts和Old Posts在<code>theme</code>中，根据不同的语言选项去修改即可。

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220413013824.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220413013824.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220413013824.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>页面背景在博文中通过Header（Meta-data）设置，批量转化的时候可以通过代码循环生成，后续进行转化的时候最好依靠随机数指定。</p>
<h3 id="github-page">Github Page</h3>
<p>安装部署插件如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">npm install hexo-deployer-git  --save</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>实际上就是将<code>public</code> 文件夹<code>push</code>到对应仓库的指定分支，有插件能够直接执行该操作，在config中执行如下设置：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">deploy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">git</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">repo</span><span class="p">:</span><span class="w"> </span><span class="l">https://github.com/&lt;yourAccount&gt;/&lt;repo&gt;</span><span class="w"> </span><span class="c"># or https://gitee.com/&lt;yourAccount&gt;/&lt;repo&gt;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">branch</span><span class="p">:</span><span class="w"> </span><span class="l">&lt;your-branch&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>之后执行 <code>hexo d</code>即可</p>
<h3 id="mathjaxtb-fix">Mathjax（TB fix）</h3>
<p>用于下一次验证的策略：手动添加MathJa支持而不基于<a href="http://masikkk.com/article/hexo-13-MathJax/" target="_blank" rel="noopener">Kramed</a>
，基于此思想迁移到<a href="https://adaning.github.io/posts/33457.html" target="_blank" rel="noopener">Mathjax3</a>
，也避免了Kramed和Prismjs的冲突。</p>
<p>支持公式的方式主要有<a href="https://dog.wtf/tech/making-hexo-next-theme-latex-math-equation-supported/" target="_blank" rel="noopener">以下</a>
的几种思路，该设置实际上主要是和Next主题相关，包括Katex等</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220413155935.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220413155935.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220413155935.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>该主题目前使用的是Mathjax + kramed + it的方式。</p>
<p>官方描述对应的Latex支持, 该部分目前的渲染效果处于玄学状态，有时候能用，有时候针对一些语法会出现渲染错误，但是并不能很好的定位到错误的原因。现象如下：</p>
<ul>
<li>缩略图中出现正常的渲染，而在正文中只显示公式</li>
<li>部分语法可以正常渲染，稍微复杂一点的无法渲染，且原因不定。</li>
</ul>
<p>目前猜测可能与Package有一定的关系，在对hexo-renderer-marked等Package进行操作后，可能就会恢复正常。</p>
<p>当前情况下在Windows清除，在WSL2中执行Hexo命令好像就可以，非常的玄学。</p>
<p>目前按照<a href="https://v-vincen.life/en/How-to-Use-Mathjax/" target="_blank" rel="noopener">主题</a>
的方式（默认已配置好），后续如果效果仍然不稳定，可能会对渲染的方式进行改动。比如利用<a href="https://linkinpark213.com/2018/04/24/mathjax/" target="_blank" rel="noopener">math的jax支持</a>
，或者基于<a href="https://hexo-next.readthedocs.io/zh_CN/latest/next/advanced/%E9%85%8D%E7%BD%AEMathJax/" target="_blank" rel="noopener">pandoc</a>
的方式把。后续再出现问题的话对比一下。</p>
<ul>
<li>利用pandoc可以完美的显示所有的LaTex，但是原有设置下Archive主页的归档信息消失：</li>
<li>基于karmx等的数学公式无法完美显示，问题有些严重，所以最终还是换了</li>
</ul>
<p>其中的一些<a href="https://blog.csdn.net/qq_44766883/article/details/107103668" target="_blank" rel="noopener">语义冲突修改</a>
倒是在新版本中，好像影响不是很明显，可能更多的是与marked的冲突，但是我们使用的是别的渲染引擎</p>
<p><strong>CDN的设置</strong>：可能需要自动<a href="https://cps.ninja/2019/03/16/hexo-with-latex/" target="_blank" rel="noopener">添加文件末尾</a>
，CDN可以自己去找一找了，把后面的对其就行</p>
<blockquote>
<p>在 ~/blog/_config.yml 文件（注意，是 Hexo 博客文件夹根目录中的 /_config.yml 而不是主题目录下的 /themes/next/_config.yml）中增加 MathJax 的支持，并手动设置下面的 src（这一步很重要，使用默认的 src 会导致数学表达式渲染显示失败。这里的关键是 src 中的 ?config=TeX-MML-AM_CHTML 这个字段）</p>
</blockquote>
<h4 id="pandoc">Pandoc</h4>
<p>MathJax + PanDoc + it的解决方案，最好部署在自己的服务器上，部署在Github上有一些折磨, Pandoc需要使用CI或者Action去部署，等熟悉了再采用该方法把。</p>
<p>pandoc 需要本机中首先安装 <a href="https://pandoc.org/installing.html#windows" target="_blank" rel="noopener">pandoc</a>
，各平台参考官方链接进行安装即可。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm uninstall hexo-renderer-kramed --save
</span></span><span class="line"><span class="cl">npm install hexo-renderer-pandoc -- save</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>（非正常方式）对于Archive的问题只需要修改一下生成Archive的路径即可，即通过修改config的生成archive和archive的路径</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220413155305.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220413155305.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220413155305.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>具体的对pandoc的配置可以参考：[Link1](<a href="https://feigeek.com/posts/b1bbb984" target="_blank" rel="noopener">https://feigeek.com/posts/b1bbb984</a>
. html)，对其一些bug的修复则用<a href="https://yidaoxiangan.com/blog/2021/03/17/Hexo%E4%BD%BF%E7%94%A8Pandoc%E6%B8%B2%E6%9F%93%E5%B8%A6%E6%9D%A5%E7%9A%84%E5%88%97%E8%A1%A8%E7%BC%A9%E8%BF%9B%E9%97%AE%E9%A2%98%E5%8F%8A%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/" target="_blank" rel="noopener">Link2</a>
，但是暂时作为可选项，新版的好像已经没有问题。</p>
<p>目前配置如下（有一些不对的冗余存在）：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mathjax: 
</span></span><span class="line"><span class="cl">  enable: <span class="nb">true</span>
</span></span><span class="line"><span class="cl">  mhchem: <span class="nb">false</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">katex: 
</span></span><span class="line"><span class="cl">  enable: <span class="nb">false</span>
</span></span><span class="line"><span class="cl">  copy_tex: <span class="nb">false</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">pandoc:
</span></span><span class="line"><span class="cl"> extensions:
</span></span><span class="line"><span class="cl">    - <span class="s1">&#39;+hard_line_breaks&#39;</span>
</span></span><span class="line"><span class="cl">    - <span class="s1">&#39;+emoji&#39;</span>
</span></span><span class="line"><span class="cl">    - <span class="s1">&#39;-implicit_figures&#39;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="prismjs">Prismjs</h3>
<p>在Hexo6.0<a href="https://sdwh.dev/posts/2022/01/Hexo-Syntax-Highlight/" target="_blank" rel="noopener">之前</a>
还是需要借助插件的，但是根据<a href="https://hexo.io/zh-cn/docs/syntax-highlight.html#PrismJS" target="_blank" rel="noopener">官方说明</a>
，在6.0之后官方已经添加了Prismjs的支持，disable Hightlight，Enable prismjs后，基于preprocess模式</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">highlight</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">enable</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">line_number</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">auto_detect</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">tab_replace</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">wrap</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">hljs</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">prismjs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">enable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">preprocess</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">line_number</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">tab_replace</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;&#39;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在对应的Theme/specific theme/layout/<code>_partial</code>/head.ejs中添加需要的css样式。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>javascript</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="o">&lt;</span><span class="nx">head</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="o">&lt;</span><span class="nx">link</span> <span class="nx">rel</span><span class="o">=</span><span class="s2">&#34;stylesheet&#34;</span> <span class="nx">href</span><span class="o">=</span><span class="s2">&#34;https://cdnjs.cloudflare.com/ajax/libs/prism-themes/1.9.0/prism-lucario.min.css&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">...</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl"><span class="o">&lt;</span><span class="err">\</span><span class="nx">header</span><span class="o">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>对应的样式可以在<a href="https://github.com/prismjs/prism-themes?utm_source=cdnjs&amp;utm_medium=cdnjs_link&amp;utm_campaign=cdnjs_library#readme" target="_blank" rel="noopener">github prismjs</a>
 中查看，其对应的cdn则按照此<a href="https://cdnjs.com/libraries/prism-themes" target="_blank" rel="noopener">链接</a>
查询，虽然不懂得javascript，但是我寻思下载到本地也是一样的，按照其他对应的prismjs-hexo-Blog中的处理即可。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>javascript</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="o">&lt;</span><span class="nx">head</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="o">&lt;</span><span class="nx">link</span> <span class="nx">rel</span><span class="o">=</span><span class="s2">&#34;stylesheet&#34;</span> <span class="nx">href</span><span class="o">=</span><span class="s2">&#34;/js/prism/prism.css&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">...</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl"><span class="o">&lt;</span><span class="err">\</span><span class="nx">header</span><span class="o">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>之后应该就可以正常使用</p>
<h3 id="password-4-blog">Password 4 Blog</h3>
<p>利用插件对特定的文章进行加密，使得特定的文章的查看需要输入密码。</p>
<p>安装插件：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">npm install --save hexo-blog-encrypt</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>快速使用: 只需要在文章的Meta信息中添加Password字段即可</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>markdown</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">---
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">password: test
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>也可进行全局加密设置：参考<a href="https://www.itfanr.cc/2021/04/16/hexo-blog-article-encryption/" target="_blank" rel="noopener">Password</a>
</p>
<h2 id="domain-setup">Domain Setup</h2>
<p><strong>腾讯云注册</strong>：首先获取一个免费的域名或是去<a href="https://dnspod.cloud.tencent.com/" target="_blank" rel="noopener">腾讯云</a>
/阿里云购买一个域名，（实名制-&gt;付钱-&gt;审核备案）</p>
<h3 id="dns-setting">DNS Setting</h3>
<p><strong>DNS解析</strong>：在购买域名的提供商为域名添加解析，以腾讯云为例：</p>
<p>（不推荐）如果想要使用ipv4，ipv6进行dns解析的话可以搜索Github Page的IP，或者</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ping username.github.io</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>（推荐）在<a href="https://console.cloud.tencent.com/domain" target="_blank" rel="noopener">域名注册控制台</a>
 选择对应的域名解析

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220413163700.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220413163700.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220413163700.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><strong>主机记录</strong>：@、www分别注册一次，分别用于https://yourdomain和 https:// www. yourdomain的解析。</p>
<p><strong>记录类型</strong>：由于同个网站的CNAME和AAAA会发生冲突，这里建议使用CNAME类型，并在后续的</p>
<p><strong>记录值</strong>: 中填写自己的username.github.io

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220413163804.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220413163804.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220413163804.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>后面有免费的SSL记得勾选，等待审核即可。</p>
<h3 id="deploy-it">Deploy it</h3>
<p><strong>Hexo部署：</strong></p>
<p>本地部署和服务启动不需要d（eploy）执行到前面即可在指定的端口查看本地的部署效果了。远程部署实际上就是<code>git Push -f</code> 到远程仓库的指定分支，完成前面github page的设置可以使用hexo -d 进行部署。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">hexo cl 
</span></span><span class="line"><span class="cl">hexo g
</span></span><span class="line"><span class="cl">hexo s
</span></span><span class="line"><span class="cl">hexo d
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">hexo cl <span class="o">&amp;&amp;</span> hexo g <span class="o">&amp;&amp;</span> hexo s <span class="o">&amp;&amp;</span> hexo d</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>Github绑定：</strong></p>
<p>在站点的source目录下创建CNAME并添加域名</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;yourDomain&#34;</span> &gt;&gt; CNAME</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在Github-&gt; Repo -&gt; Settting -&gt; Page —&gt; Custom Domain 中填写域名并保存，等待解析完成后，即可。</p>
<p>参考资料：<a href="https://cloud.tencent.com/developer/article/1834163" target="_blank" rel="noopener">Link1</a>
、<a href="http://t.zoukankan.com/zengmianhui-p-12634066.html" target="_blank" rel="noopener">Link2</a>
</p>
<h2 id="themes-switch">Themes Switch</h2>
<p>主题之间的切换应该和我预想的一致，下载主题到对应的Theme文件夹，在最外层的_Config中切换，但是由于我们的初始主题Live my LIfe极度依赖默认<code>_config.yml</code>，而非自身目录下的配置文件。故而有以下的几点工作</p>
<ul>
<li><strong>Compatibility Check</strong>： config setting，plugin version and dependencies conflics</li>
<li><strong>Dir structure</strong>： check the consistency of the dir tree structure</li>
<li><strong>Find themes u like</strong>: latex-support，post-style，archive，tag，Difficulty，Long-Time-Support&hellip;</li>
</ul>
<p>以下这些是一些初步筛选出来的觉得还可以的主题，之后可以切换看看：</p>
<ol>
<li><a href="http://miccall.tech/2018/12/05/Shader/toolbag3%20Shader/" target="_blank" rel="noopener">画廊</a>
 Miccall主页为画廊的基本样式，有对应的图库功能，作为图片和效果展示的话可能还不错，post页面和标签等页面较为一般。</li>
<li><a href="https://tridiamond.tech/" target="_blank" rel="noopener">三钻主题</a>
，亮色惊艳，暗色太花，设计难度和修改难度估计较大，Archive为时间轴模式，大爱，可以的话看看怎么将LivemyLife的Archive也变为这种样式。正文的效果以及对应的TOC</li>
<li><a href="https://www.iequa.com/" target="_blank" rel="noopener">极简程序员博客</a>
，简洁美但是稍微有点太简洁，Archive界面好像崩了</li>
<li><a href="https://blinkfox.github.io/" target="_blank" rel="noopener">闪耀狐</a>
，LTS，分类的雷达图，标签的热力图大爱，想办法搞到自己的主题里，功能较为全面和完善，如果想要自定义或者添加一些功能，完全可以参考这个主题。</li>
<li><a href="https://hexo.io/themes/" target="_blank" rel="noopener">Find More</a>
 官方主题游廊</li>
</ol>
<p>当前对各方各面的概念还不是太理解，后面考虑对网页构建的底层，以及其他的相关知识进行进一步的了解，方便自己对网站进行更进一步的自定义。</p>
<h2 id="public">Public</h2>
<p>站点提交，通过将自己的网页提交给搜索引擎，使得自己的文章能够被搜索到，目前暂时先不考虑Public，所以这里先行占位，功能暂时不进行支持。</p>
<p>主要参考<a href="https://www.hansion.win/2020/04/13/hexo-bo-ke-deng-jing-tai-wang-ye-ti-jiao-bai-du-he-google-gu-ge-shou-lu/" target="_blank" rel="noopener">Link1</a>
，初步计划使用sitemap进行站点提交，由于baidusitemap存在较多冲突考虑先不启用。后续进行继续实验。</p>
<h2 id="reference">Reference</h2>
<ol>
<li><a href="https://segmentfault.com/a/1190000017986794" target="_blank" rel="noopener">基础+百度网站提交</a>
 | <a href="https://hackmd.io/@Heidi-Liu/note-hexo-github#%E4%BB%80%E9%BA%BC%E6%98%AF-Hexo%EF%BC%9F" target="_blank" rel="noopener">基础解读</a>
 |</li>
<li><a href="https://hexo.io/zh-tw/docs/configuration" target="_blank" rel="noopener">Official SIte</a>
： 介绍默认_config文件的配置信息</li>
<li><a href="https://yesmore.cc/cn/hexo-livemylife/#Mathjax%E6%B8%B2%E6%9F%93%E9%85%8D%E7%BD%AE" target="_blank" rel="noopener">简单修改</a>
livemylife主题的一些简单修改</li>
<li><a href="https://zhuanlan.zhihu.com/p/26625249" target="_blank" rel="noopener">知乎教程</a>
 可以添加网易云音乐的外链，同时有我们需要的自定义社交网络按钮的部分（基于Next）去看看用的是什么插件，怎么嵌入。</li>
<li><a href="https://zhuanlan.zhihu.com/p/33616481" target="_blank" rel="noopener">zhihu2</a>
，基本同上，但是多了一些其他的自定义的</li>
<li>大小写的改变不会git推送，导致发生<a href="https://www.lovesofttech.com/general/hexoTagsAndCategories404Error.html" target="_blank" rel="noopener">404</a>
错误</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>Vim 01 Recorder</title>
      <link>https://aikenh.cn/posts/vimoperation/</link>
      <pubDate>Thu, 07 Apr 2022 14:15:25 +0000</pubDate>
      <guid>https://aikenh.cn/posts/vimoperation/</guid>
      <description>recorder of neovim</description>
      <content:encoded><![CDATA[<p><strong>Chose Your Dotfile to start the vim</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">vim -u <span class="o">{</span>path to your .vimrc<span class="o">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="recorder-of-vim">Recorder of Vim</h2>
<p>This Chapter mainly introduces the <strong>Recorder</strong> in vim,Which is used to do some <strong>repeated</strong> operations.This function is also called a <strong>macro</strong>.</p>
<p>for more information try <code>:help recording</code></p>
<h3 id="registersrelated-with-recording">Registers(related with recording)</h3>
<p>This section will introduce related <strong>concept/function</strong> of recording function. Which help us to understand how this works, and what we should pay attention to it.</p>
<p><strong>register of vim</strong>: register is a superset of macro, it contains more function. In this part we should know, register can <strong>store</strong> some string or operations to help subsequent use.</p>
<p><strong>Status</strong>:
Using <code>:registers</code> or <code>:reg</code> to check those <strong>we have registered</strong>, or add the registers&rsquo;s name behind to show those u&rsquo;re interested in.</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>vim</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vim" data-lang="vim"><span class="line"><span class="cl"><span class="p">:</span><span class="nx">reg</span> <span class="nx">a</span> <span class="nx">b</span> <span class="nx">c</span> 
</span></span><span class="line"><span class="cl"><span class="p">---</span> <span class="nx">Registers</span> <span class="p">---</span>
</span></span><span class="line"><span class="cl"><span class="c">&#34;a register a content</span>
</span></span><span class="line"><span class="cl"><span class="c">&#34;b register b content</span>
</span></span><span class="line"><span class="cl"><span class="c">&#34;c register c content</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>Lifecycle</strong>
The information in registers will <strong>not disappear</strong> with the window closed. But maybe with the system-level&rsquo;s open-close. we should <strong>test this</strong>!!! So we can store some <strong>snippet</strong>,<strong>pwd</strong>,etc.</p>
<p><strong>Pick</strong>
There are many registers like <code>0~9</code>,<code>a~z</code>,unnamed,etc. <code>0~9</code> are the <strong>default registers</strong> for many operations like del,copy,command,etc.<br>
So for recording, we better using <code>a~z</code>. And It should be noted that the upper version <code>A~Z</code> means add operations to an existing command.&lsquo;a~z&rsquo; is to overwrite it.</p>
<p><strong>Modified</strong>
Besides the <code>A~Z</code> works like <code>append</code> in python. There are several way to <strong>modify</strong> the registers;
Like:</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>vim</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vim" data-lang="vim"><span class="line"><span class="cl"># <span class="nx">using</span> <span class="s1">&#39;w&#39;</span> <span class="nx">as</span> <span class="nx">an</span> <span class="nx">example</span> <span class="nx">of</span> <span class="nx">reg</span>.
</span></span><span class="line"><span class="cl"><span class="p">:</span><span class="k">let</span> @<span class="nx">w</span><span class="p">=</span><span class="s1">&#39;&lt;what command u want&gt;&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># <span class="nx">general</span> <span class="nx">version</span> <span class="nx">is</span>: <span class="p">(</span><span class="nx">ignore</span> <span class="nx">the</span> []<span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">:</span><span class="k">let</span> @[<span class="nx">reg</span> <span class="nx">u</span> <span class="nx">want</span> <span class="nx">to</span> <span class="nx">modify</span>]<span class="p">=</span><span class="s1">&#39;[what command u want]&#39;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>TODO: we should write a indipendent chapter for the registers in vim.</p>
<h3 id="usage">Usage</h3>
<p>This section shows the Usage of Recording. And we will continue to collect some good examples. Then put it below.</p>
<ul>
<li>Change to <strong>Normal</strong> mode and <strong>pressed</strong> &ldquo;q&rdquo;</li>
<li>Chose reg u want (<code>a~z</code> normally) to start record a macro</li>
<li>{ <strong>operations</strong> u want to be recorde }</li>
<li>-&gt;in <strong>non-insert</strong> mode&lt;- <strong>pressed</strong> &ldquo;q&rdquo; to end recording</li>
<li>Using &ldquo;@+reg&rdquo; to repeat this operations/macro</li>
<li><code>10@+reg</code> to repeat this macro 10times</li>
</ul>
<p><strong>Example1</strong> setting the pwd/useid of server.<br>
<strong>Example2</strong> fill up some sheet infomation.</p>
<h2 id="references">References</h2>
<p><strong>recording</strong></p>
<ul>
<li>official doc : <code>:help recording</code></li>
<li><a href="https://einverne.github.io/post/2017/11/vim-registers.html" target="_blank" rel="noopener">registers in vim</a>
</li>
<li><a href="https://juejin.cn/post/6906120745228632077" target="_blank" rel="noopener">registers in vim2</a>
</li>
<li><a href="https://www.jianshu.com/p/f08ed3d6273e" target="_blank" rel="noopener">how to use recording in vim</a>
</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>使用 PicGo 设置图床</title>
      <link>https://aikenh.cn/posts/picbed/</link>
      <pubDate>Sun, 27 Mar 2022 09:19:23 +0000</pubDate>
      <guid>https://aikenh.cn/posts/picbed/</guid>
      <description>Github | Tencent-COS</description>
      <content:encoded><![CDATA[<p>@Aiken 2020 first write，2021 modify</p>
<p>Mainly using picgo-core(command line) to setting picbed，and we can update the setting method</p>
<h2 id="github">Github</h2>
<ul>
<li><a href="#Pic-Bed">使用PicGo-Core（command line）设置github图床，自动转义url</a>
</li>
<li><a href="#Git">插入自动复制图片，使用git上传github</a>
</li>
</ul>
<h3 id="基本部署">基本部署</h3>
<ol>
<li>在偏好设置中的图像，进行如下设置👇： 下载或更新PicGo-Cord(command line)</li>
</ol>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200512160643588.png">
    <img alt="image-20200512160643588" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200512160643588.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200512160643588.png" style="display: block; margin: 0 auto;"
      alt="image-20200512160643588"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ol start="2">
<li>
<p>接着去Github中建立一个Repo：UserName/RepoName，用以存放图片（Public），简单的用readme初始建立即可。</p>
</li>
<li>
<p>在Github的setting - developer setting-personal access tokens中新建token，指定简单的repo权限，并记录个人的token（只显示一次）
<strong>Attention：</strong> 忘记记录的话，在token中也是通过update token（好像是这个名，获取新的值的）</p>
</li>
<li>
<p>用Typora打开配置文件设置，或者使用命令行进行配置</p>
</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>json</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">       <span class="nt">&#34;picBed&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">           <span class="nt">&#34;github&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">             <span class="nt">&#34;repo&#34;</span><span class="p">:</span> <span class="s2">&#34;UserName/RepoName&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">             <span class="nt">&#34;token&#34;</span><span class="p">:</span> <span class="s2">&#34;your github token here&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">             <span class="nt">&#34;path&#34;</span><span class="p">:</span> <span class="s2">&#34;img/&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">             <span class="nt">&#34;customUrl&#34;</span><span class="p">:</span> <span class="s2">&#34;https://raw.githubusercontent.com/UserName/RepoName/master&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">             <span class="nt">&#34;branch&#34;</span><span class="p">:</span> <span class="s2">&#34;master&#34;</span>
</span></span><span class="line"><span class="cl">           <span class="p">},</span>
</span></span><span class="line"><span class="cl">           <span class="nt">&#34;current&#34;</span><span class="p">:</span> <span class="s2">&#34;github&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">           <span class="nt">&#34;uploader&#34;</span><span class="p">:</span> <span class="s2">&#34;github&#34;</span>
</span></span><span class="line"><span class="cl">         <span class="p">},</span>
</span></span><span class="line"><span class="cl">         <span class="nt">&#34;picgoPlugins&#34;</span><span class="p">:</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="5">
<li>点击验证图片上传选项，进行测试，成功即可</li>
</ol>
<h3 id="存在问题">存在问题</h3>
<p>用Github做图床的话，上传不是十分的稳定（可能需要依赖科学上网技术。请八仙过海，各显神通）。可以用其他的服务器作图床，大体过程应该也差不多，后续个人有更换的话在进行补充。</p>
<ol>
<li>在其他的pc上可以使用相同的token进行复用，但是在进行测试的时候要记得将repo中的两张测试图片删除，不然可能会导致验证失败的问题。</li>
</ol>
<h2 id="picgo-with-obsidian-etc">PicGo With Obsidian etc.</h2>
<p>这种方法可能是最稳健的泛化能力也最强，再很多编辑器类似的地方都能用，但是前提就是我们进行笔记撰写的时候要把picgo的客户端打开。</p>
<ol>
<li>安装<code>picgo</code>客户端，（在其中安装你对应图床的插件）</li>
</ol>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211227165330.png">
    <img alt="gitee" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211227165330.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211227165330.png" style="display: block; margin: 0 auto;"
      alt="gitee"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ol start="2">
<li>和上述描述的一样再gitee或者github中设置相应的图床token等，并在软件中填写对应的token</li>
<li>picgo设置中，打开server即可</li>
<li>再Obsidian中安装插件 <code>image auto upload plugin</code> 并在其中设置本地<code>ip:port</code>即可</li>
</ol>
<h2 id="cos-in-tencent-cloud">COS in tencent-cloud</h2>
<p>相关网站：<a href="https://console.cloud.tencent.com/cos" target="_blank" rel="noopener">Tencent-Cloud-Cos</a>

参考资料：<a href="https://sspai.com/post/64169" target="_blank" rel="noopener">Create-Tencent-Cloud-Cos</a>
, <a href="https://jy741.github.io/2020/05/14/%E8%85%BE%E8%AE%AF%E4%BA%91%E5%9B%BE%E5%BA%8A/" target="_blank" rel="noopener">Setting-Your-PicGoApp</a>
</p>
<h3 id="创建存储桶">创建存储桶</h3>
<ol>
<li>
<p>Create Store-Bucket(Private write Public read) -&gt;</p>
</li>
<li>
<p>Create A sub-User(which only got access for the cos R/W) -&gt;</p>
<blockquote>
<p>QcloudCOSFullAccess, Pic Below to add the access</p>
</blockquote>
</li>
<li>
<p>generate a private_token -&gt;</p>
<blockquote>
<p>token manage</p>
</blockquote>
</li>
<li>
<p>cp SecretID,SecretKey,Main_Account_ID,name_of_bucket to PicGo</p>
<blockquote>
<p>the area in the second figure</p>
</blockquote>
</li>
</ol>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220327174117.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220327174117.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220327174117.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>


<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220327174402.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220327174402.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220327174402.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="picgo-设置">Picgo 设置</h3>
<ul>
<li>进入腾讯云的对象存储页面：
<ul>
<li>存储桶列表中可以看到存储桶名称，即Bucket</li>
<li>所属地域，也就是设定存储区域如：ap-guangzhou</li>
</ul>
</li>
<li>右上角的用户信息中点击访问管理进入到用户界面
<ul>
<li>用户-&gt; 子用户可以看到账号 ID：即Appid</li>
<li>点击子账户进入详情页-&gt;API 密钥
<ul>
<li>SecretId</li>
<li>SecretKey</li>
</ul>
</li>
</ul>
</li>
<li>设置完成即可。</li>
</ul>
<h2 id="gitee防盗链事件后抛弃">Gitee（防盗链事件后抛弃）</h2>
<p>因为gitee是国内的github，服务器比较稳定，所以我们也可以使用gitee作为我们更为稳定的图床；</p>
<p>两个链接合起来才是好用的，都有一些冗余：</p>
<ul>
<li><a href="https://zhuanlan.zhihu.com/p/145960692" target="_blank" rel="noopener">Typora+picgo-core+gitee</a>
</li>
<li><a href="https://blog.csdn.net/weixin_42230956/article/details/111349889" target="_blank" rel="noopener">PicGo-core+Gitee+Typora</a>
</li>
</ul>
<h3 id="gitee基本部署">gitee基本部署</h3>
<ul>
<li>
<p>安装Node，npm；</p>
</li>
<li>
<p>安装picgo-core的命令行命令：</p>
</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">  npm install picgo -g</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>安装gitee的插件：</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">  picgo install super-prefix
</span></span><span class="line"><span class="cl">  picgo install gitee-uploader</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="配置gitee-repo">配置Gitee Repo</h3>
<ul>
<li>
<p>初始化一个repo，保存URL中的User/repo，不要轻信标题，因为有昵称机制。</p>
</li>
<li>
<p>在个人资料中初始化个人的Token，勾选<code>projects</code>选项即可;</p>
</li>
</ul>
<h3 id="设置配置文件">设置配置文件</h3>
<p>基于picgo的命令，会自动的更新Json文件，我们不许需要</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">picgo <span class="nb">set</span> uploader
</span></span><span class="line"><span class="cl"><span class="c1"># up to the command hint, we input those messages</span>
</span></span><span class="line"><span class="cl">1.按上下键找到gitee，回车    
</span></span><span class="line"><span class="cl">2.repo：用户名/仓库名 （打开自己的仓库，浏览器里的网址username/reponame）    
</span></span><span class="line"><span class="cl">3.token：刚才生成的token    
</span></span><span class="line"><span class="cl">4.path:路径，写仓库的名字就是reponame    
</span></span><span class="line"><span class="cl">5.custompath:不用填，回车   
</span></span><span class="line"><span class="cl">6.customURL:不用填，回车    
</span></span><span class="line"><span class="cl"><span class="c1"># finish setting process</span>
</span></span><span class="line"><span class="cl">picgo use uploader</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script>]]></content:encoded>
    </item>
    <item>
      <title>Fine Tuning</title>
      <link>https://aikenh.cn/posts/finetune/</link>
      <pubDate>Tue, 08 Feb 2022 14:31:37 +0000</pubDate>
      <guid>https://aikenh.cn/posts/finetune/</guid>
      <description>Design and code fine-tune in pytorch</description>
      <content:encoded><![CDATA[<p>@Langs: python, torch
@reference: d2l-pytorch，<a href="https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html" target="_blank" rel="noopener">transfer_torch</a>
</p>
<p>This Note focus on the code part.
模型微调和模型预训练，在Pytorch中的使用方式对比汇总。</p>
<h2 id="how-to-design-the-fine-tune">How to Design the Fine Tune</h2>
<p>这一部分主要集中于我们对于微调任务的拆解，有几种不同的预训练和微调的方式，在不同的情景下，对应的参数应该怎么设置和调整是问题的重点。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211205143153.png">
    <img alt="WorkFlow" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211205143153.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211205143153.png" style="display: block; margin: 0 auto;"
      alt="WorkFlow"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>基于这种Transfer的策略，我们能够学习到一个更通用，泛化能力更强，有助于识别边缘，色彩，等等有助于下游任务的通用特征提取。</p>
<p>在Transfer任务中，有几种不同的调整方式：</p>
<ul>
<li>固定Bakcbone，只训练Classifier</li>
<li>同步微调网络</li>
<li>区分学习率，微调Backbone，训练Classifirer</li>
</ul>
<p>为了实现这几种不同的Transfer方式，需要用到以下的几种方式：梯度截断，lr区分设置等。</p>
<h2 id="code-part">Code Part</h2>
<h3 id="不同lr设置">不同lr设置</h3>
<p><strong>微调Backbone，训练Classifier</strong>作为最经典的Transfer设定，在Code上也较为复杂，所以我们首先举个这种例子。</p>
<p>相关的文档可以参考：<a href="https://pytorch-cn.readthedocs.io/zh/latest/package_references/torch-optim/" target="_blank" rel="noopener">torch.optim</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># get dataset</span>
</span></span><span class="line"><span class="cl"><span class="n">train_img</span> <span class="o">=</span> <span class="n">torchvision</span><span class="o">.</span><span class="n">datasets</span><span class="o">.</span><span class="n">ImageFolder</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">data_dir</span><span class="p">,</span> <span class="s1">&#39;train&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># get new model</span>
</span></span><span class="line"><span class="cl"><span class="n">pretrained_new</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">expand_dim</span><span class="p">(</span><span class="n">dim</span><span class="o">=</span><span class="n">out_dim</span><span class="p">,</span><span class="n">re_init</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># pre train it 定义一个用于微调的函数</span>
</span></span><span class="line"><span class="cl"><span class="c1"># pytorch可以通过字典的形式来区分对设置lr</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">train_fine_tuning</span><span class="p">(</span><span class="n">net</span><span class="p">,</span> <span class="n">learning_rate</span><span class="p">,</span> <span class="n">batch_size</span><span class="o">=</span><span class="mi">128</span><span class="p">,</span> <span class="n">num_epoch</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">diff_lr</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">	<span class="c1"># set dataloader</span>
</span></span><span class="line"><span class="cl">	<span class="n">train_iter</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">utils</span><span class="o">.</span><span class="n">Dataloader</span><span class="p">(</span><span class="n">train_img</span><span class="p">,</span> <span class="n">batch_size</span><span class="o">=</span><span class="n">batch_size</span><span class="p">,</span> <span class="n">shuffle</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="n">test_iter</span> <span class="o">=</span> <span class="o">...</span>
</span></span><span class="line"><span class="cl">	
</span></span><span class="line"><span class="cl">	<span class="c1"># set loss</span>
</span></span><span class="line"><span class="cl">	<span class="n">loss</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">CrossEntropyLoss</span><span class="p">(</span><span class="n">reduction</span><span class="o">=</span><span class="s1">&#39;none&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	
</span></span><span class="line"><span class="cl">	<span class="c1"># set diff lr for diff part of it </span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="n">diff_lr</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="n">params_1x</span> <span class="o">=</span> <span class="p">[</span><span class="n">param</span> <span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="n">param</span> <span class="ow">in</span> <span class="n">net</span><span class="o">.</span><span class="n">name_parameters</span><span class="p">()</span> <span class="k">if</span> <span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&#34;fc.weight&#34;</span><span class="p">,</span> <span class="s2">&#34;fc.bias&#34;</span><span class="p">]]</span>
</span></span><span class="line"><span class="cl">		<span class="n">trainer</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">optim</span><span class="o">.</span><span class="n">SGD</span><span class="p">([{</span><span class="s1">&#39;params&#39;</span><span class="p">:</span> <span class="n">params_1x</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">								  <span class="p">{</span><span class="s1">&#39;params&#39;</span><span class="p">:</span> <span class="n">net</span><span class="o">.</span><span class="n">fc</span><span class="o">.</span><span class="n">parameters</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">								  <span class="s1">&#39;lr&#39;</span><span class="p">:</span> <span class="n">learning_rate</span> <span class="o">*</span><span class="mi">10</span><span class="p">}],</span>
</span></span><span class="line"><span class="cl">								  <span class="n">lr</span><span class="o">=</span><span class="n">learning_rate</span><span class="p">,</span> <span class="n">weight_decay</span><span class="o">=</span><span class="mf">0.001</span>
</span></span><span class="line"><span class="cl">								 <span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="n">trainer</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">optim</span><span class="o">.</span><span class="n">SGD</span><span class="p">(</span><span class="n">net</span><span class="o">.</span><span class="n">parameters</span><span class="p">(),</span> <span class="n">lr</span><span class="o">=</span><span class="n">learning_rate</span><span class="p">,</span> <span class="n">weight_decay</span><span class="o">=</span><span class="mf">0.001</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>同时不用担心，scheduler可以将我们的两组lr同时进行更新，可以基于下面的代码进行测试</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">optimizer</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">optim</span><span class="o">.</span><span class="n">SGD</span><span class="p">([{</span><span class="s1">&#39;params&#39;</span><span class="p">:</span> <span class="p">[</span><span class="n">torch</span><span class="o">.</span><span class="n">rand</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">requires_grad</span><span class="o">=</span><span class="kc">True</span><span class="p">)]},</span>
</span></span><span class="line"><span class="cl">                            <span class="p">{</span><span class="s1">&#39;params&#39;</span><span class="p">:</span> <span class="p">[</span><span class="n">torch</span><span class="o">.</span><span class="n">rand</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">requires_grad</span><span class="o">=</span><span class="kc">True</span><span class="p">)],</span><span class="s1">&#39;lr&#39;</span><span class="p">:</span> <span class="mf">0.01</span><span class="p">}],</span> 
</span></span><span class="line"><span class="cl">                            <span class="n">lr</span><span class="o">=</span><span class="mf">0.1</span><span class="p">,</span> <span class="n">momentum</span><span class="o">=</span><span class="mf">0.9</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">scheduler</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">optim</span><span class="o">.</span><span class="n">lr_scheduler</span><span class="o">.</span><span class="n">StepLR</span><span class="p">(</span><span class="n">optimizer</span><span class="p">,</span> <span class="n">step_size</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">gamma</span><span class="o">=</span><span class="mf">0.1</span><span class="p">,</span> <span class="n">verbose</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">epoch</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">10</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">scheduler</span><span class="o">.</span><span class="n">step</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Epoch-</span><span class="si">{0}</span><span class="s1"> lr: </span><span class="si">{1}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">epoch</span><span class="p">,</span> <span class="n">optimizer</span><span class="o">.</span><span class="n">param_groups</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s1">&#39;lr&#39;</span><span class="p">]))</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Epoch-</span><span class="si">{0}</span><span class="s1"> lr: </span><span class="si">{1}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">epoch</span><span class="p">,</span> <span class="n">optimizer</span><span class="o">.</span><span class="n">param_groups</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="s1">&#39;lr&#39;</span><span class="p">]))</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="梯度截断">梯度截断</h3>
<p><a href="https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html" target="_blank" rel="noopener">PyTorch Docs</a>
</p>
<p><strong>保留Backbone，训练Classifier</strong>，截断网络向Backbone的回传，设置学习率仅训练分类器。</p>
<p>表面上写的梯度截断，实际上我们需要做的就是不让优化器优化模型即可，不需要截断梯度的运算，也就是在optim的参数种不添加其他部分的网络即可,</p>
<p>也就是反向一下上面的params_1x即可，然后添加对应的参数。</p>
<p>还有另一种方式，也是官方的实现，也就是使用require_grad来对不需要进行梯度计算的单元进行覆盖设置。
具体的代码可以参考如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="n">params</span> <span class="ow">in</span> <span class="n">model</span><span class="o">.</span><span class="n">name_parameters</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span><span class="p">[</span><span class="s1">&#39;fc.weight&#39;</span><span class="p">,</span> <span class="s1">&#39;fc.bias&#39;</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl">		<span class="n">params</span><span class="o">.</span><span class="n">require_grad</span> <span class="o">=</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">parameters</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">model</span><span class="o">.</span><span class="n">parameters</span><span class="p">()</span> <span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">require_grad</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">parameters</span><span class="p">)</span> <span class="o">==</span> <span class="mi">2</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="加载部分模型">加载部分模型</h3>
<p>在自监督学习中，只加载Backbone或者只加载Classifier的情况是非常常见的，这就需要我们仅仅加载部分的参数，为了实现该目标，我们可以按照如下的方式进行操作</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 读取训练好的模型参数，获取当前模型的字典</span>
</span></span><span class="line"><span class="cl"><span class="n">ckpt</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">pretrain_opt</span><span class="p">[</span><span class="s1">&#39;pth&#39;</span><span class="p">])[</span><span class="s1">&#39;model&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">model_dict</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">state_dict</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 获取特定的‘key’将该字典用来更新模型的参数</span>
</span></span><span class="line"><span class="cl"><span class="n">pretrain_dict</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span><span class="n">v</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span><span class="n">v</span> <span class="ow">in</span> <span class="n">ckpt</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="k">if</span> <span class="s1">&#39;backbone&#39;</span> <span class="ow">in</span> <span class="n">k</span> <span class="ow">and</span> <span class="s1">&#39;fc&#39;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">k</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 更新模型的dict后进行载入</span>
</span></span><span class="line"><span class="cl"><span class="n">model_dict</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">pretrain_dict</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">model</span><span class="o">.</span><span class="n">load_state_dict</span><span class="p">(</span><span class="n">model_dict</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>函数中的<code>update</code>需要参数的<code>key</code>和模型中的字典完全匹配，结构相同也不行，因此，在这里还会遇到一个另外的问题就是，<strong>模型名称失配问题</strong>。</p>
<p>而为了解决这个问题，最简单直接的方法就是，修改对应的key，最内层基本都是一致的，名称上的区别只在于，我们外层的结构不同。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">pre_projector_dict</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;classifier.&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">):</span><span class="n">v</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span><span class="n">v</span> <span class="ow">in</span> <span class="n">ckpt</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="k">if</span> <span class="s1">&#39;classifier&#39;</span> <span class="ow">in</span> <span class="n">k</span><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>由此便可以完成对部分模型的加载和匹配。</p>
]]></content:encoded>
    </item>
    <item>
      <title>Git 01 入门与常用操作</title>
      <link>https://aikenh.cn/posts/git_manual1/</link>
      <pubDate>Tue, 01 Feb 2022 12:19:34 +0000</pubDate>
      <guid>https://aikenh.cn/posts/git_manual1/</guid>
      <description>config git, usage, remote, bugs fixed</description>
      <content:encoded><![CDATA[<p>参考文献：<a href="https://juejin.cn/post/7131713973572861966" target="_blank" rel="noopener">稀土掘金</a>
 | ProGit2</p>
<h2 id="git-与-svn-的区别">GIT 与 SVN 的区别</h2>
<p>SVN 是集中式版本控制系统，其所有的版本管理都是集中在某个中央服务器，因此，在干活的时候，首先都需要从中央服务器中获取最新的版本，修改后将版本推送到中央服务器，因此大多数场景下需要进行联网使用。可能会更依托于相应的图形化客户端来进行同步和版本管理，便于管理美术资源等等。</p>
<p>GIT 是分布式版本管理系统，每个人的电脑就是一个完整的版本库，可以进行独立的版本管理，多人协作可能依托于 github 之类的中继节点，将修改同步给对方，解决冲突。</p>
<h2 id="init-初始化">Init 初始化</h2>
<p>包含 ssh 的详细指令在 ssh 的文档中，这边只介绍设置完这一系列操作之后的 git 初始化，主要是初始化 ssh，并将私钥放到 github 或者 gitee 的账户中。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git config --global user.name <span class="s2">&#34;YourName&#34;</span>
</span></span><span class="line"><span class="cl">git config --global user.email <span class="s2">&#34;YourEmailAdress&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 查看相关的配置信息</span>
</span></span><span class="line"><span class="cl">git config --list
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 设置CRLF和LF的相关转换 第一条在提交的时候自动抓换位LF，迁出转换为CRLF</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 第二条拒绝混合换行符的提交</span>
</span></span><span class="line"><span class="cl">git config --global core.autocrlf <span class="nb">true</span>
</span></span><span class="line"><span class="cl">git config --global core.safecrlf <span class="nb">true</span> </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="github-设置">Github 设置</h3>
<p>官方文档介绍的一些权限错误的地址：&lt; <a href="https://docs.github.com/en/github/authenticating-to-github/error-permission-denied-publickey%3e" target="_blank" rel="noopener">https://docs.github.com/en/github/authenticating-to-github/error-permission-denied-publickey></a>
</p>
<p>将本机的 ssh 公钥(public)放到 GITHUB 账户下的 ssh 管理地址，执行测试</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">ssh -T git@github.com</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>没有问题的话就可以直接进行 clone，之类的 git 操作了</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># 小trick，不拉取历史的commit</span>
</span></span><span class="line"><span class="cl">git clone --depth<span class="o">=</span><span class="m">1</span> REPO_ADRESS</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="gitignore-文件编写">Gitignore 文件编写</h3>
<p>参考文件：【 <a href="https://www.cnblogs.com/kevingrace/p/5690241.html" target="_blank" rel="noopener">Git忽略提交规则</a>
 】【 <a href="https://github.com/github/gitignore" target="_blank" rel="noopener">gitignore 各语言模版</a>
 】</p>
<p>首先创建对应的 <code>.gitignore</code> 文件，根据自己的需求编写内容，这里也<strong>推荐</strong>通过 VsCode 的插件或者使用上述仓库中<strong>对应语言的模版文件</strong>来创建初始化 ignore 文件，会包含一些常用的通常无需上传的本地配置或者本地缓存等内容；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">touch .gitignore</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在覆盖了这些通用的忽略项后，可以根据项目情况添加特有的路径，通常主要包括以下的几类：</p>
<ul>
<li><strong>大文件</strong>：如自用的测试数据等</li>
<li><strong>敏感配置文件</strong>：包含了敏感信息的配置项等（这里建议考虑使用 env 等，或者上传对应的 default 文件）</li>
<li><strong>日志文件</strong></li>
</ul>
<h3 id="设置-git-的代理">设置 Git 的代理</h3>
<p>设置全局代理使用如下的方式：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git config --global http.proxy 127.0.0.1:1080
</span></span><span class="line"><span class="cl">git config --global https.proxy 127.0.0.1:1080</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>同理取消全局代理如下</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git config --global --unset http.proxy  
</span></span><span class="line"><span class="cl">git config --global --unset https.proxy</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="常用指令与架构介绍">常用指令与架构介绍</h2>
<p>Git 整体的使用架构如<a href="https://juejin.cn/post/7131713973572861966" target="_blank" rel="noopener">下图所示</a>
，一般而言开发者在工作区进行当前修改，将需要同步或者发布的修改内容通过暂存区存储到本地 &amp; 远程仓库中，结合远程仓库的协作特性和分支功能，可以实现同个项目的多人同步分离开发，同时开发多种功能等。</p>
<p>因此 Git 或者 Svn 等 CLI 的使用技能，在公司中或者在项目参与中是相当重要的，建议每个人程序开发者都能对其有一定的了解。</p>
<div align=center><img src=" https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20221204135313.png" style="zoom: 75%;" ></div>
<p>下面是一些基本的命令使用，其中许多命令都有一些额外的参数可供使用，如果经常使用 Git 建议可以简单阅读一下 <strong>ProGit</strong>。</p>
<blockquote>
<p>这里会简单记录一些命令，其中那些在 git 使用中会有所提示的命令就不再赘述，例如 pull 别的分支的时候取消 merge 到当前分支的 git merge &ndash;abort 之类就会有所提示。</p>
</blockquote>
<table>
  <thead>
      <tr>
          <th>普通</th>
          <th>command</th>
          <th>分支</th>
          <th>command</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>创建本地 repo</td>
          <td>git init</td>
          <td>创建/显示分支</td>
          <td>git branch name</td>
      </tr>
      <tr>
          <td>工作区状态</td>
          <td>git status</td>
          <td>切换分支</td>
          <td>git checkout [branch]</td>
      </tr>
      <tr>
          <td>添加到暂存区</td>
          <td>git add /.</td>
          <td>切换</td>
          <td>git checkout -b name</td>
      </tr>
      <tr>
          <td>暂存区到本地</td>
          <td>git commit -m ‘mesg’</td>
          <td>合并分支</td>
          <td>git merge branch</td>
      </tr>
      <tr>
          <td>日志</td>
          <td>git log (–oneline)</td>
          <td>删除分支</td>
          <td>git branch -d</td>
      </tr>
      <tr>
          <td>拉取远程库</td>
          <td>git pull / git fetch</td>
          <td>推送本地分支</td>
          <td>git push origin branch</td>
      </tr>
      <tr>
          <td>克隆远程库</td>
          <td>git clone</td>
          <td></td>
          <td></td>
      </tr>
      <tr>
          <td><strong>撤销</strong></td>
          <td></td>
          <td><strong>标签</strong></td>
          <td></td>
      </tr>
      <tr>
          <td>撤销工作区修改</td>
          <td>git checkout – file-name</td>
          <td>创建标签</td>
          <td>git tag tag-name</td>
      </tr>
      <tr>
          <td>撤销暂存区修改</td>
          <td>git reset HEAD file-name</td>
          <td>显示所有标签</td>
          <td>git tag</td>
      </tr>
      <tr>
          <td>撤销本地库修改</td>
          <td>git reset –hard commitID</td>
          <td>删除标签</td>
          <td>git tag -d tag</td>
      </tr>
      <tr>
          <td><strong>远程</strong></td>
          <td></td>
          <td><strong>储藏</strong></td>
          <td>·</td>
      </tr>
      <tr>
          <td>同步本地库和</td>
          <td>git remote add origin xx@y repo</td>
          <td>保存现场</td>
          <td>git stash</td>
      </tr>
      <tr>
          <td>远程库</td>
          <td>git push -u origin master</td>
          <td>恢复现场</td>
          <td>git stash pop</td>
      </tr>
  </tbody>
</table>
<h3 id="commit-规范和相关命令">Commit 规范和相关命令</h3>
<p>commit 命令实现将&quot;将暂存区的文件以特定的注释提交到仓库中&quot;，提交的 Message 建议建立统一的规范，这样可以方便后续使用 log 查阅的时候定位到特定修改的 commit。</p>
<h4 id="message-standard-标准提交内容">Message Standard 标准提交内容</h4>
<p>本人推荐的 Commit Message 格式如下，该格式并非是一成不变的，可以根据仓库中存放的项目类型来灵活变更 Tag 的数量和内容。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git commit -m <span class="s2">&#34;[tag1(modify scope)] [tag2(modify type)]: excatly modify info&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>Tag1 (modify scope): 说明修改的内容，泛一些例如修改代码 code，资源 res，细一些则例如修改的文件夹 tool、util</li>
<li>Tag2（modify type）：说明修改的类型，主要有：<code>Feat</code>、<code>Fix</code>、<code>Refactor</code>、<code>Style</code>、<code>Test</code>、<code>Docs</code>、<code>Merge</code>，如果修改的是资源等文件可以忽略。</li>
<li>Modify info：修改的详细信息，说明修改的目的和修改的内容即可</li>
</ul>
<p>例如以下的几个写法：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git commit -m <span class="s2">&#34;[res]: add presonal conf file&#34;</span>
</span></span><span class="line"><span class="cl">git commit -m <span class="s2">&#34;[code-util][Feat]: add function to parser conf file&#34;</span>
</span></span><span class="line"><span class="cl">git commit -m <span class="s2">&#34;[code &amp; res][Feat &amp; Fix]: add function for merge conf, fix bug on parser conf, add my conf resource&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>该部分没有什么硬性要求，只需要自己能够清晰的看懂自己的 commit 且具备一致性即可。</p>
<h4 id="extra-operation-撤销重写合并">Extra Operation 撤销、重写、合并</h4>
<blockquote>
<p>有时候针对已经提交的 Commit 不满意，或者有一些新的更改需要添加到上一次的 Commit 中，可以参考下面的操作。</p>
</blockquote>
<p><strong>撤销</strong> Commit 或者<strong>重写</strong> Commit Message</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git reset --soft HEAD^  <span class="c1"># 撤销当前commit</span>
</span></span><span class="line"><span class="cl">git commit --amend      <span class="c1"># 重写当前commit</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>合并多次 Commit</strong>：通过 rebase 命令来进行 merge，该命令通过整理多次的 Commit 来使得整个提交历史更为整洁有序，但是需要额外的精力去整理就是。具体的操作流程如下：</p>
<ol>
<li>首先查看 commit 的 hash</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git log</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="2">
<li>找到需要修改的 commit 的<strong>前一个</strong> commit 的 ID</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># 找到需要合并的最早commit的上一个的ID</span>
</span></span><span class="line"><span class="cl">git rebase -i &lt;ID&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 也可以使用以下命令合并header往前多少n次的commit</span>
</span></span><span class="line"><span class="cl">git rebase -i HEAD~n</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>square：将该次 commit 和上一次 commit 合并</li>
<li>pick：保留该次 commit</li>
</ul>
<p>通过修改 commit 提交界面的 square 和 pick 即可实现多次 commit 的合并。</p>
<h3 id="history-历史查看">History 历史查看</h3>
<p>查看当前分支的提交历史只需要通过 <code>git log</code> 即可看到基本的提交信息，这里简要介绍一些参数来帮助更清晰的定位 commit</p>
<ul>
<li><code>git log -p -{n}</code>: 参数 <code>-p</code> 以 diff 的形式在显示基本提交信息的基础上还显示该提交的具体修改内容，由于内容较多；可以通过 <code>-{n}</code> 仅显示最近 n 次提交的内容</li>
<li><code>git log --stat</code> ：参数 <code>--stat</code> 显示每次提交的统计信息，包含修改的文件以及对该文件修改的行数的统计信息</li>
<li><code>git log --graph</code>： 参数 <code>--graph</code> 会使用简单的 ASCII 图像来可视化提交之间的分支关系，也就是 vscode 中 gitgraph 的命令行版本，可以帮助了解提交之间的合并和起始提交等信息</li>
</ul>
<p>此外还有诸如 <code>--pretty</code> 等参数可以自定义 log 显示的具体格式，需要的话可以参阅 progit 或者官方文档进行了解。</p>
<h3 id="add-一些额外操作">Add 一些额外操作</h3>
<p>Add 命令主要将修改的内容提交到暂存区，不仅可以作为我们一次次的中间存储节点，也是为后续的提交做缓冲，但是难免会遇到以下的情况：</p>
<ul>
<li>提交错文件或者修改了结构需要将一个或者多个文件从暂存区中撤退出来；</li>
<li>清除工作区中不需要提交的临时文件</li>
</ul>
<p>如果是撤销所有提交的文件：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git reset HEAD .</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>撤销特定文件的提交</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git reset HEAD &lt;file&gt;</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>以上两个命令不需要记录，只需要使用 <code>git status</code> 查看当前状态的时候会有提示。</p>
<p>清除工作区中不需要提交的临时文件，可以使用以下的命令</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git clean -nf <span class="c1"># 查看会被清除的未追踪文件</span>
</span></span><span class="line"><span class="cl">git clean -f  <span class="c1"># 清除未追踪的文件</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果涉及到文件夹可以添加参数 d</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git clean -ndf <span class="c1"># 查看会被清除的未追踪文件和文件夹</span>
</span></span><span class="line"><span class="cl">git clean -fd  <span class="c1"># 实际执行清除指令</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>其中-n 参数为查看而不实际执行的参数，避免文件的误删。具体可以通过 <code>git help clean</code> 查看。</p>
<h3 id="cherrypick-挑选-commit">CherryPick 挑选 Commit</h3>
<blockquote>
<p>仅简要介绍其作用，详细使用等后续有使用场景再来补充。</p>
</blockquote>
<p>Git CherryPick 命令实现从别的分支挑<strong>选某个 Commit 的修改合并到当前分支中</strong>，该命令在一些提交数少的分支中，可以代替 merge，实现一个更为线性整洁的 Master 分支。</p>
<p>可以结合 Rebase 合并提交使用，由此得到一个更为干净的提交历史。</p>
<h2 id="暂存区--stash">暂存区 &amp; Stash</h2>
<p>暂存区指的是 git add. 后存储到的区域，用来作为本地和仓库之间的缓存。</p>
<h3 id="暂存区处理">暂存区处理</h3>
<p>清除暂存区某个文件的指令（通常是为了修改.gitignore）的时候执行</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git rm -r --cache filename</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>看暂存区有什么文件</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git ls-files
</span></span><span class="line"><span class="cl">git status</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="stash-区域使用">stash 区域使用</h3>
<p>是一个特殊的区域，本地的 git 存储区，一般来说使用场景较少，例如以下的场景。</p>
<blockquote>
<p>本地改了代码，但是突然有个人过来问你另一个分支的问题，同时这个时候你在实现某个功能，实现一半，又不想提交到 Git 仓库中，那么你就可以考虑使用 <code>git stash save &quot;临时存一下&quot;</code>，这个时候它就会帮你存到这个储存区，你去其他分支做完事情回来，再 <code>git stash pop</code>就好了。</p>
</blockquote>
<p>主要使用的就是以下的几个命令：</p>
<ul>
<li><code>git stash save &quot;message&quot;</code> 将当前的修改暂存</li>
<li><code>git stash list</code> 查看暂存了哪些修改</li>
<li><code>git pop </code> 默认使用存储的堆栈中的第一个 stash</li>
<li><code>git stash apply stash@{n}</code> 使用第 n+1 个 stash，n 从 0 开始。</li>
</ul>
<p>一般建议是不要使用太多的 stash，这样一个 save 和一个 pop 命令就可以 handle 。</p>
<blockquote>
<p>如果 pop 操作导致冲突，希望撤销 <code>git stash pop</code> 行为，可以使用 <code>git reset --hard</code> 回退当前修改，该操作会保留 pop 出来的修改仍然在 stash 中。</p>
</blockquote>
<h2 id="一些-git-工作流介绍">一些 Git 工作流介绍</h2>
<h3 id="使用-git-rebase-保持简洁的-history">使用 Git Rebase 保持简洁的 History</h3>
<p>参考资料： <a href="https://www.cnblogs.com/FraserYu/p/11192840.html" target="_blank" rel="noopener">优雅且安全的使用 GitRebase</a>
</p>
<blockquote>
<p>前文已经介绍过了 git rebase 用于合并 merge 的功能，这里主要介绍的是 git rebase 在分支合并中的作用，何时在分支管理中使用 git rebase 取代 git merge 来进行分支合并。</p>
</blockquote>
<p>git merge 是一种非破坏性的操作，当我们使用 git merge 进行分支合并的时候，会提供一个新的 commit ，其内容为两个分支的合并提交，这也是与 rebase 最大的区别。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240804121843.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240804121843.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240804121843.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>rebase 正如其单词所言，re-base，重构我们的 base，我们可以使用下面的命令将 master 分之合并到我们的 dev 分支中：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git checkout dev
</span></span><span class="line"><span class="cl">git rebase master</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这会将我们的 dev 分支的新增内容移动到 master 分支之后，相当于重新构建了 dev 分支上的每个 commit，将其在新的 master 之后再合入。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240804122136.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240804122136.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/mac/20240804122136.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>使用这种方式的话，项目的历史记录会更为线性，会使得分支的提交历史更加整洁，没有不必要的合并提交，考虑到可能在开发过程中我们可能会多次需要更新 master 分支的内容，这样能让我们的更新更加容易追溯和复原。</p>
<p>此外正如合并多次 commit 的操作，使用 -i 可以开启 rebase 的交互模式，交互模式中我们就可以将多次提交浓缩为单次提交(squash)，或者合并某两个连续的提交(fixup)。</p>
<blockquote>
<p>tips: 如果需要一次性将从 master 分出来的 dev 上的第一个提交到最后一个 dev 上的提交合并，避免用 Head~n 去数，或者手动去找对应的 commitID，也可以用 <code>git merge-base dev master</code>  代替，这里的 master 就是你的切出 dev 的原始分支，不一定是 master。</p>
</blockquote>
<p>但是由于 rebase 操作是一个破坏性的操作，会修改我们之前的每次原始提交，因此在使用的时候需要慎重，遵循 rebase 使用的法则：<strong>永远不要再公共分支上使用它</strong>，在公共分支使用会导致所有人的原始 master 和远端无法对齐，导致一系列问题。</p>
<p>但是如果别人同样在远程开发 dev 分支，我们 fetch 后同样可以考虑使用 merge 或者 rebase 更新 dev 分支本身，因为这只影响了我们 local 端的后续提交。BTW，<code>git pull --rebase</code> 可以强制使用 rebase 的方式来集成远程分支。</p>
<p>最终开发完成后，使用 rebase 更新分支上 master 的内容，再去 master 上 merge，会产生最好的线性历史记录，也确保不会影响他人的开发：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git checkout dev
</span></span><span class="line"><span class="cl">git rebase master
</span></span><span class="line"><span class="cl">git checkout master
</span></span><span class="line"><span class="cl">git merge dev
</span></span><span class="line"><span class="cl">git push origin master:master</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果不确定 rebase 的使用是否正确，可以复制一个临时分支来执行 rebase，如果不小心搞乱了，还可以有原始的分支来复原。</p>
<h3 id="使用-git-merge---squash-保持简洁-history">使用 Git Merge &ndash;squash 保持简洁 History</h3>
<p>除了上述使用 rebase 将分支上的 commit 逐个移动到 master 分支之后，进而维持 master 上的线性提交历史，上述还提到可以使用 rebase 合并多次 commit 后进行提交，但由于 rebase 本身会改变开发分支，所以实际上更推荐仅在 Merge 的时候进行分支上的 commit 合并（例如开发分支上的 commit 较为随意的情况），这种情况下可以在 rebase 的时候使用-i 操作或者使用 <code>git merge --squash {branch} </code> 进行 merge</p>
<h3 id="远程协作">远程协作</h3>
<p>考虑多用户，多分支的在线场景，如何有效的 Pull &amp; Push.</p>
<h4 id="在本地仓库切换默认提交用户">在本地仓库切换默认提交用户</h4>
<p>在多用户的终端场景，推送前记得切换相关的用户设置。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git config --local user.name <span class="s2">&#34;YourName&#34;</span>
</span></span><span class="line"><span class="cl">git config --local user.emali <span class="s2">&#34;YourEmail&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="推送拉取远程分支">推送、拉取远程分支</h4>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># 冒号前本地，冒号后远程，</span>
</span></span><span class="line"><span class="cl">git push origin local_branch:remote_branch
</span></span><span class="line"><span class="cl">git pull origin remote_branch:local_branch</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="仅-clone-指定分支">仅 Clone 指定分支</h4>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git clone -b <span class="o">{</span>branch<span class="o">}</span> <span class="o">{</span>rep<span class="o">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="拉取代码解决冲突">拉取代码解决冲突</h4>
<p>git fetch 实际上 pull = fetch + merge，可以解决完冲突再进行代码提交，相对 pull 更安全，结合 Vscode 中的 Gitgraph 等，用于解决冲突和验证修改方面更为安全简单。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git fetch
</span></span><span class="line"><span class="cl">git log -p FETCH_HEAD
</span></span><span class="line"><span class="cl">git merge FETCH_HEAD</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>通过使用 Stash 的方式，同样可以避免再拉取远程代码的时候不覆盖本地的代码，灵活选用吧，一般情况下使用 fetch 已经足够。</p>
<h2 id="一些工具">一些工具</h2>
<p>一些好用的 CLI（命令行工具）和 VsCode 插件推荐：</p>
<ul>
<li><a href="https://github.com/jesseduffield/lazygit" target="_blank" rel="noopener">Lazygit</a>
（命令行工具，带一个比较酷炫的 GUI）</li>
<li>Gitlens（VsCode）：在编辑界面显示每行代码的提交者，丰富 github 的 git 拓展选项</li>
<li>Gitgraph（VsCode）：方便查看每次 commit 的修改内容，用对比窗口显示，便于发现冲突解决和修改内容</li>
<li>Beyond Compare（差异对比工具）：类似 diff 命令，非常好用的对比和修改不同版本的文件，文件夹之间的差异。</li>
<li>Win Merge （差异对比工具）： BC 的免费替代品，基本上是足够使用的。</li>
<li>还有一些诸如 tortoise 和 github 客户端等图形界面也可供尝试</li>
</ul>
<h2 id="troubleshooting">Troubleshooting</h2>
<h3 id="从-commit-中删除大文件">从 Commit 中删除大文件</h3>
<p>避免.git 目录占用过多存储，这一部分写的有点小瑕疵，到时候就看超链接</p>
<p><a href="https://www.zhihu.com/question/29769130/answer/315745139" target="_blank" rel="noopener">郑宇</a>
；主要是要将大文件排除追踪，在 push 之前都还是比较好解决的，但是如果已经提交上去了就稍微比较麻烦，尝试将其中的大文件删掉。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># 1. 运行gc，生成pack文件`–prune = now` 表示对所有的文件都做修剪</span>
</span></span><span class="line"><span class="cl">git gc --prune<span class="o">=</span>now
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 2. 找出最大的k个文件，以3为例</span>
</span></span><span class="line"><span class="cl">git verify -pack -v .git/objects/pack/*.idx <span class="p">|</span>sort -k -3 -n <span class="p">|</span>tail -3
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># bug: cannot open ///bad ..</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 可能是由于地址出错了，修改地址，如下是查看地址的代码</span>
</span></span><span class="line"><span class="cl">find .git/objects/ -type -f
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 3. 查看那些大文件究竟是谁，按照上一步输出的hash value 进行搜索，（不用全长）</span>
</span></span><span class="line"><span class="cl">git rev-list --objects --all <span class="p">|</span>grep &lt;hashvalue&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 4. 移除对该文件的追踪引用</span>
</span></span><span class="line"><span class="cl">git filter-branch --force --index-filter <span class="s2">&#34;git rm --cache --ignore-unmatch &#39;&lt;FILENAME HERER&gt;&#39;&#34;</span> --prune-empty --tag-name-filter cat -- --all
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 5. 进行repack</span>
</span></span><span class="line"><span class="cl">git <span class="k">for</span>-each-ref --format<span class="o">=</span><span class="s1">&#39;delete %(refname)&#39;</span> refs/original <span class="p">|</span> git update-ref --stdin
</span></span><span class="line"><span class="cl">git reflog expire --expire<span class="o">=</span>now --all
</span></span><span class="line"><span class="cl">git gc --prune<span class="o">=</span>now
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 6. 查看pack的空间使用情况</span>
</span></span><span class="line"><span class="cl">git count-objects -v
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 7. 强制推送重构大文件</span>
</span></span><span class="line"><span class="cl">git push origin local-b:remote-b --force</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="连接问题">连接问题</h3>
<ol>
<li><strong>openssl error 10054</strong></li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"> git config --global http.postBuffer <span class="m">524288000</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="2">
<li><strong>time out port443</strong></li>
</ol>
<p>just wait for some time，应该是代理的问题，不行就使用国行版 github 把</p>
<ol start="3">
<li><strong>server certificate verification failed. CAfile</strong></li>
</ol>
<p>使用<code>github.com.cnpmjs.org</code>国内镜像站的时候，可能会出现权限的问题，这种情况下就要对 git 的证书验证命令做调整，有两种策略，执行其中一种：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git config --global http.sshverify false</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># carry out in the </span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">GIT_SSL_NO_VERIFY</span><span class="o">=</span><span class="m">1</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>之后我们就可以正常的使用镜像站对原有的 repo 进行更新和拉取了，比如说 omz update.</p>
<h2 id="tobecontinue">ToBeContinue</h2>
<ul>
<li>Git Rebase专题：<a href="https://juejin.cn/post/7123826435357147166" target="_blank" rel="noopener">GIt Merge和Git Rebase的区别</a>
</li>
<li>Git Reset 和 Git Cherrypick 专题：<a href="https://juejin.cn/post/7131713973572861966" target="_blank" rel="noopener">紧急修复</a>
</li>
<li>Git tag 专题开发标签</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Linux 文件传输和同步</title>
      <link>https://aikenh.cn/posts/transfer-sync-files/</link>
      <pubDate>Mon, 17 Jan 2022 03:11:41 +0000</pubDate>
      <guid>https://aikenh.cn/posts/transfer-sync-files/</guid>
      <description>using crontab, rsync, scp</description>
      <content:encoded><![CDATA[<p>@aikenhong 2022</p>
<p>当我们需要在Server之间进行，或者Server和WSL之间进行文件的传输，以及文件夹的同步的时候，如果要打开Xftp之类的软件进行，有繁琐的操作中转，或者说目录较为庞杂的时候，也显得有些麻烦。</p>
<p>于是我们可能希望使用脚本，来实现更便捷，同时也能设置定时功能，使得操作简单便捷，经过简单的调研，我们目前尝试使用以下几种方法，并取得了成功。</p>
<h2 id="rsync-同步目录">Rsync 同步目录</h2>
<p>rsync是借助ssh服务进行的文件传输，为了使用起来方便，我们首先需要配置免密登录，在服务器之间传输SSH密钥，参考[[Envs/SSH]]</p>
<p>此后我们便可以编写同步脚本来同步远程的目录和本地目录，当然也可以执行反向的命令，</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">rsync -azP --delete -e <span class="s1">&#39;ssh -p port&#39;</span> --progress --stats --exclude <span class="s2">&#34;big Files or sth&#34;</span> user@ip:source_path target_path &gt;transfer.log</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>根据 <code>-progress</code> 和 <code>-stats</code> 选项记录传输过程中的日志，并输出到 transfer.log(如果加入计划任务 crontab 记得使用绝对路径)，同时使用 exclude 排除大文件，避免传输过慢。</p>
<blockquote>
<p>-a: 归档文件模式（保留文件的时间戳等），保括了 r 的递归
-z: 使用压缩文件传输
-P: 支持断点续传
&ndash;delete: 会删除目标文件中多出来的东西，保持同步，使得成为远程的镜像，但是有时候我们可能不需要这点，避免同步损毁</p>
</blockquote>
<p>此外 <code>-e -p &lt;port&gt;</code> 用于指定服务器的端口，在使用过程中也可能会遇到在目标服务器上权限不足的问题，如果配置了对应的免密登录等，可以添加以下的选项来提权 <code>--rsync-path=&quot;sudo rsync&quot;</code></p>
<p>Reference 参考文献：</p>
<ul>
<li><a href="https://cloud.tencent.com/developer/article/1490094?from=article.detail.1813628" target="_blank" rel="noopener">Ubuntu使用Rsync远程备份</a>
</li>
<li><a href="https://www.ruanyifeng.com/blog/2020/08/rsync.html" target="_blank" rel="noopener">阮一峰的rsync详细讲解</a>
</li>
<li><a href="https://unix.stackexchange.com/questions/541200/rsync-permission-denied-13-what-am-i-doing-wrong" target="_blank" rel="noopener">Rsync权限不足</a>
</li>
</ul>
<h2 id="scp传输特定文件">SCP传输特定文件</h2>
<p>Linux scp文件传输命令用于Linux之间复制文件和目录，全称“secure copy”，基于SSH进行的安全的远程文件拷贝命令</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">model</span><span class="o">=</span><span class="s1">&#39;local file&#39;</span>
</span></span><span class="line"><span class="cl">scp -P port <span class="nv">$model</span> user@remote_ip:remote_folder</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><a href="https://www.runoob.com/linux/linux-comm-scp.html" target="_blank" rel="noopener">菜鸟教程scp参数介绍</a>
</p>
<p>出现问题：permission denied：使用chmod 修改远程文件夹权限，774 or 777</p>
<h2 id="crontab定时执行脚本">Crontab定时执行脚本</h2>
<p>实际上本篇章应该在后续移动到Linux笔记中，是一个定期执行程序的命令，我们可以通过这个命令来定期执行我们的脚本</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">crontab -l 
</span></span><span class="line"><span class="cl">crontab -e
</span></span><span class="line"><span class="cl">sudo nvim /etc/rsyslog.d/50-default.conf 开启cron.log
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">重启相关服务
</span></span><span class="line"><span class="cl">sudo service rsyslog restart
</span></span><span class="line"><span class="cl">sudo service cron restart</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>编辑定时设置：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="m">30</span> <span class="m">10</span> * * * path/file.sh &gt;&gt; logfile.log</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>修改要调用的sh文件的权限</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo chmod <span class="m">777</span> file.sh </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><a href="https://www.runoob.com/linux/linux-comm-crontab.html" target="_blank" rel="noopener">菜鸟教程</a>
</p>
<h2 id="szrz传输文件">SZ、RZ传输文件</h2>
<p>sz、rz命令是Linux、Unix与Windows进行ZModem文件传输的命令；</p>
<p>安装<code>lrzsz</code>：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo apt-get install lrzsz</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li><code>sz</code>： sent zmodern 从服务器传输文件到的本地</li>
<li><code>rz</code>：reveice 从windows传递文件到Linux服务器</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>IL Collection</title>
      <link>https://aikenh.cn/posts/il-collection/</link>
      <pubDate>Tue, 04 Jan 2022 01:38:04 +0000</pubDate>
      <guid>https://aikenh.cn/posts/il-collection/</guid>
      <description>Incremental Learning</description>
      <content:encoded><![CDATA[<p>@AikenHong 2022</p>
<p>[[Draft/IL 总结]]: Thx 2 wyz to provide some clus for learnning Incremental Learning.</p>
<p>In this Doc, we may add some related knowledge distill works which is used to design our Incremental Structure.
在这个文档中，我们可能还会添加一些知识蒸馏的相关工作的文献，这些实际上对于我的增量学习架构有一个比较大的启发</p>
<ul>
<li><a href="https://blog.csdn.net/weixin_36474809/article/details/116176371" target="_blank" rel="noopener">DER</a>
</li>
<li>SPPR 没有 get 到方法到底是怎么做的</li>
</ul>
<h2 id="introduction-">Introduction 👿</h2>
<p>在很多视觉应用中，需要在保留旧知识的基础上学习新知识，==举个例子==，理想的情况是，我们可以保留之前学习的参数，而不发生==灾难性遗忘==，或者我们基于之前的数据进行协同训练，灾难性遗忘是 IL 中最核心的问题。</p>
<p>Incremental 的基本过程可以表示如下<sub>[4]</sub>：

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220106101003.png">
    <img alt="dsa" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220106101003.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/20220106101003.png" style="display: block; margin: 0 auto;"
      alt="dsa"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>我们将模型可以划分为以下的两个部分<sub>[1]</sub>：backbone 和 classifier

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220105213925.png">
    <img alt="split" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220105213925.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220105213925.png" style="display: block; margin: 0 auto;"
      alt="split"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>从 LWF 中我们可以知道经典的 Paradigm，主要有下面的三种来对 $\theta _S$ 和 $\theta_o$ 来进行更新：</p>
<ul>
<li>仅重新训练分类器：仅更新 $\theta_o$</li>
<li>微调特征提取器，重新训练分类器</li>
<li>联合训练</li>
</ul>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220106111235.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220106111235.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220106111235.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="基于蒸馏架构的方法">基于蒸馏架构的方法</h2>
<p>这一系列的方法实际上是 IL 最经典的发展路线，实际上从初始的蒸馏架构开始，最后逐渐的发展到结合回放的策略中，我认为结合<strong>rehearsal</strong>才是该类方法最后的归宿，所以我将基于蒸馏正则化的 Pod 和 LWF 也放到了这一部分。</p>
<h3 id="motivation">Motivation</h3>
<p>《Learning without Forgetting》LWF 主要带来的就是将 KD 损失引入 Joint Training 的范式，也就是我们印象中最原始的增量学习的途径，利用 <code>expand_dim</code> 训练最后输出的新的节点，但是这个范式是不需要旧数据。</p>
<div>
$$ 
Loss = L_{CE} + L_{KD}
 $$
</div>
<p>这里的蒸馏使用的是最终的 pred 输出，后续对于蒸馏损失的有 KDC 的变体，根据新旧样本的比例来赋予权重，考虑模型优化的权重。</p>
<div>
$$ 
Loss = \lambda L_{CE} + (1-\lambda) L_{KD}
 $$
</div>
<p>其中 $\lambda^2 = \frac{|C_{old}|}{|C_{old}|+ |C_{new}|}$</p>
<p>这就是最经典的 Incremental Learning 的范式，我们首先继承一部分分类器的参数，然后通过这个损失对整个框架进行协同训练。</p>
<h3 id="引入旧样例">引入旧样例</h3>
<p>《ICaRL: Incremental Classifier and Representation Learning》在 LWF 基础上引入部分旧数据来避免灾难遗忘的问题</p>
<ul>
<li>基于特征提取器对新旧数据的训练集提取==平均特征向量==（Kmeans + KNN）</li>
<li>基于最近邻均值分类算法 NME 计算出新旧数据的预测值 计算 LWF 的经典损失，优化模型</li>
</ul>
<blockquote>
<p>本文的亮点主要在于引入了旧的数据进行复习（有一个比较好的数据选取策略），以及最后使用的不是全连接层而是最近邻分类器来作为预测。（Will This Get Better？）</p>
</blockquote>
<p>后续在 ==《End-to-End Incremental Learning》== 中，将最近邻分类器替换成分类层，其动机就是对 ICaRL 进行优化。</p>
<p><strong>memory 保存旧样本 -&gt; CE+KD -&gt; reBalance + Fine-tune</strong></p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220106112111.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220106112111.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220106112111.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>由于数据量上的有偏，导致分类器会严重有偏与 New-Classes，但是我认为这个可能是对于场景设定的不同，加入新的需求和发现少量的数据两者是一个比较大的不同。</p>
<p>这里的 <strong>样本选择策略</strong> 可能在后续会比较有用。</p>
<ul>
<li>在 ICaRL 中选择的是最确信的样本来 rehearsal，也就是使用特征中心的 KNN 方法来选取样本。</li>
<li>而在==《Rainbow Memory》==<sub>[8]</sub>中则是选择最难的样本，其 motivation 是选择最接近判别界样本</li>
</ul>
<p>RM 的最终实现的思路是通过 Data Augmentation 对样本进行变化，将不同 Augmentaion 后的预测的偏差（不确定程度）来衡量一个样本是 Hard or Simple Task，基于这种方式来选择 Hard-Task（Uncertainty）</p>
<p>具体而言，标签为 c 的样本，经过 perturbed 后，被网络预测为 c 类的次数越多，则不确定性越弱。</p>
<h3 id="优化分类器">优化分类器</h3>
<p>由于新类的大量数据带来的偏差，==《Large Sacale Incremental Learning》== 试图解决这个问题</p>
<ul>
<li>将训练集划分一个 rebalance 的 dataset 作为验证集，并用该数据集训练一个 Bias Correction Layer 得到修正的参数，</li>
</ul>
<p>该层的输出如下，实际上就是一个线性回归层，只有两个参数</p>
<div>
$$ 
q_{k}=\left\{\begin{array}{lr}
o_{k} & 1 \leq k \leq n \\
\alpha o_{k}+\beta & n+1 \leq k \leq n+m
\end{array}\right.
 $$
</div>
<p>训练该层的时候固定 CLF 和 BB，使用 CE 损失即可，但是模型在大数据集上的表现更佳，在 cifar100 的小数据集上表现一般。</p>
<p>另外还有借助 Long-Tailed 中的策略，从 $||W||$ 的角度矫正偏差的文章 ==《Learning a Unified Classifier Incrementally via Rebalancing》==</p>
<p>动机是由于：1）imbalance：new classes 的权重的大小远远高于 old classes 的权重。2）特征与 old classes 的权重关系没有保留。3）一些 new classes 的权重与 old classes 的权重相近（容易混淆的类别），导致歧义性。</p>
<p>引入了 Cosine Normalization 分类器，实际上就是进分类器之前进行正则化，加入 Margin 损失（可以参考人脸比对的 Cosine Face 之类的）最终损失为：</p>
<div>
$$ 
L=\frac{1}{|\mathcal{N}|} \sum_{x \in \mathcal{N}}\left(L_{\mathrm{ce}}(x)+\lambda L_{\mathrm{dis}}^{\mathrm{G}}(x)\right)+\frac{1}{\left|\mathcal{N}_{\mathrm{o}}\right|} \sum_{x \in \mathcal{N}_{\mathrm{o}}} L_{\mathrm{mr}}(x)
 $$
</div>
<p>更简单的有==《Maintaining discrimination and fairness in class incremental learning》==，通过对于分类器中的新旧模型的**weight **做 Rescale 使其再 W 上达成一致来维持一个较好的效果</p>
<div>
$$ 
\begin{gathered}
W = (W_{old},W_{new}) ; Norm_{old} = (||W_1||, ···, ||W_{c^b_{old}}) \\
\gamma = \frac{Mean(Norm_{old})}{Mean(Norm_{new}} \\
\hat{W}_{new} = \gamma · W_{new} \\
\end{gathered}
 $$
</div>
<h3 id="优化特征提取器">优化特征提取器</h3>
<p>其实Incremental现阶段的任务也倾向于使用两阶段的架构，基于这样的架构，我们首先提名最重要的就是基于SCL的这篇文章<sub>[9]</sub>,这篇文章主要的思路是：</p>
<center>SCL+projector（Train）+NCM（Test）</center>
<p>训练的Batch就是普通的Memory+New，但是值得一提的是，这篇文章对Memory的数据选取做了消融实验，得到了这样的结果：</p>
<p><strong>随机选取</strong>Memory的效果&gt;GSS（NIPS2019）和ASER（AAAI2021），是一个令人惊讶的结果.</p>
<p>而类似的，也有使用图像旋转的SSL（缓解ce带来的特征bias）+CE结合Prototype（rehearsal避免遗忘）+ KDLoss的研究<sub>[14]</sub>，证明了结合类似的自监督任务能够有效缓解特征之间的重叠。</p>
<p>使用的SSL任务是常见的Rotate Loss, KD是和上一轮的模型做约束。</p>
<div>
$$ 
L_{t,total} = L_{t,ce} + \lambda L_{t,protoAug} + \gamma L_{t,kd}
 $$
</div>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220107221329.png">
    <img alt="Feature Compare" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220107221329.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220107221329.png" style="display: block; margin: 0 auto;"
      alt="Feature Compare"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>同样的C<sup>2</sup>OL<sub>[15]</sub> 这篇方法，就用最基本的对比学习的损失来研究该方法对于IL的实用性，也发现了基于CL学出来的特征确实更适合用在蒸馏的任务之上，验证了我们的猜想。</p>
<h3 id="优化损失设计">优化损失设计</h3>
<p>《PODNet Pooled Outputs Distillation for Small-Tasks Incremental Learning》基于样本回放的方法，改进 KD，定义了 Pooled Output Distillation。</p>
<ul>
<li>spatial-based distillation-loss，基于空间的蒸馏损失，改进蒸馏方法</li>
<li>representation comprising multiplt proxy vectors，代理向量改进了分类器</li>
</ul>
<p>==part1 Update KD Loss==</p>
<center> Pooling 简略图</center>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220106095511.png">
    <img alt="pooling" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220106095511.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220106095511.png" style="display: block; margin: 0 auto;"
      alt="pooling"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>假设： $\hat{y} = g(f(x))$ 为分类过程，其中 $f(x)$ 代表特征提取过程。
POD 算法则为，不仅将蒸馏应用到特征提取的最终输出，还将其用于 $f(x)$ 的中间过程的输出</p>
<div>
$$ 
f^t(x) = f^t_L .. ·f^t_l .. ·f^t_1(x)
 $$
</div>
<p>中的每一层（如下式）都作为中间的结果，用来做 KD，上标 t 表示 task，下标则表示模型第几层。</p>
<div>
$$ 
h^t_{l,c,w,h} = f^t_l(·)
 $$
</div>
<p>对该输出的各层执行各种级别的 POD 蒸馏，作为我们的监督来实现对灾难性遗忘的避免：</p>
<div>
$$ 
\mathcal{L}_{\text {POD-pixel }}\left(\mathbf{h}_{\ell}^{t-1}, \mathbf{h}_{\ell}^{t}\right)=\sum_{c=1}^{C} \sum_{w=1}^{W} \sum_{h=1}^{H}\left\|\mathbf{h}_{\ell, c, w, h}^{t-1}-\mathbf{h}_{\ell, c, w, h}^{t}\right\|^{2}
 $$
</div>
<p>显然 pixel 级别对于模型的约束是最强的</p>
<div>
$$ 
\begin{gathered}
\mathcal{L}_{\text {POD-channel }}\left(\mathbf{h}_{\ell}^{t-1}, \mathbf{h}_{\ell}^{t}\right)=\sum_{w=1}^{W} \sum_{h=1}^{H}\left\|\sum_{c=1}^{C} \mathbf{h}_{\ell, c, w, h}^{t-1}-\sum_{c=1}^{C} \mathbf{h}_{\ell, c, w, h}^{t}\right\|^{2} \\
\mathcal{L}_{\text {POD-gap }}\left(\mathbf{h}_{\ell}^{t-1}, \mathbf{h}_{\ell}^{t}\right)=\sum_{c=1}^{C}\left\|\sum_{w=1}^{W} \sum_{h=1}^{H} \mathbf{h}_{\ell, c, w, h}^{t-1}-\sum_{w=1}^{W} \sum_{h=1}^{H} \mathbf{h}_{\ell, c, w, h}^{t}\right\|^{2} \\
\mathcal{L}_{\text {POD-width }}\left(\mathbf{h}_{\ell}^{t-1}, \mathbf{h}_{\ell}^{t}\right)=\sum_{c=1}^{C} \sum_{h=1}^{H}\left\|\sum_{w=1}^{W} \mathbf{h}_{\ell, c, w, h}^{t-1}-\sum_{w=1}^{W} \mathbf{h}_{\ell, c, w, h}^{t}\right\|^{2}
\end{gathered}
 $$
</div>
<p>pixel 级别的蒸馏对于模型限制比较严格，其他级别的对于模型限制相对较松，需要一个权衡，作者最终选用的是 Spatial 级别的蒸馏，相当于 width 和 height 层面蒸馏 loss 之和</p>
<div>
$$ 
\mathcal{L}_{\text {POD-spatial }}\left(\mathbf{h}_{\ell}^{t-1}, \mathbf{h}_{\ell}^{t}\right)=\mathcal{L}_{\text {POD-width }}\left(\mathbf{h}_{\ell}^{t-1}, \mathbf{h}_{\ell}^{t}\right)+\mathcal{L}_{\text {POD-height }}\left(\mathbf{h}_{\ell}^{t-1}, \mathbf{h}_{\ell}^{t}\right)
 $$
</div>
<p>特征提取模型最终的特征则使用 pixel 级别的蒸馏：</p>
<div>
$$ 
\mathcal{L}_{POD-flat}(h^{t-1},h^t) = ||h^{t-1} - h^t||^2
 $$
</div>
<p>将这些蒸馏损失整合起来取代原本的 KD-Loss，再加上我们的 CE 即可：</p>
<div>
$$ 
\begin{gathered}
\mathcal{L}_{POD-final} = \frac{\lambda_c}{L-1}\sum_{l=1}^{L-1} \mathcal{L}_{POD-spatial}(f_l^{t-1}(x),f_l^t(x)) +  \\
\lambda_f \mathcal{L}_{POD-flat}(f_l^{t-1}(x),f_l^t(x))
\end{gathered}
 $$
</div>
<p>==Part2 Local Similarity Classifier==</p>
<p>第一个改进点就是将 Loss 修正为 Cosine 的形式<sub>UCiR</sub>，实际上就是使用的归一化后的 FC 层，但是如果只使用一个 Cos 相似度，好像多样化的需求无法满足，需要类似一个多头的机制</p>
<blockquote>
<p>和 LT 的地方一样，IL 近年来的主要架构也是两部分进行分离的，所以我们可以考虑从我们的角度来实现类似 POD-Loss 的架构维持，也就是一定程度上为我们的 SSL-SCL 架构的可行性提供了一定的信心。</p>
</blockquote>
<p>该方法迄今为止还是很多增量任务的榜单前几，该方法的蒸馏性能也被验证为有效，但是实际上将该方法用于模型中需要增加大量的特征输出模块，整体架构上修改起来可能会较为复杂。</p>
<h2 id="基于模型结构的方法">基于模型结构的方法</h2>
<p>这一部分不是我研究的重点，可以看到有一部分设计的拓张模型或者，堆叠模型，用额外的结构来承载对应的新类的研究，可能考虑到一部分参数公用然后实行协同判断的策略把。</p>
<p>或者是其他的图模型，拓扑结构（神经气体网络）等等的方法，拓扑结构等方法可能户籍是未来的一个方向。</p>
<h3 id="特征网络堆叠">特征网络堆叠</h3>
<ul>
<li>DER 特征网络堆叠的方法</li>
</ul>
<h2 id="其他方法">其他方法</h2>
<ul>
<li><a href="https://www.pnas.org/content/pnas/114/13/3521.full.pdf" target="_blank" rel="noopener">EWC</a>
 ：这类方法一般是对网络中每个参数的重要性进行评估，根据每个参数的重要性，调整梯度信息更新参数。</li>
<li></li>
</ul>
<h2 id="其他问题">其他问题</h2>
<p>这里会收集一部分 IL 中存在的一些现象或者问题</p>
<h3 id="新类优于旧类">新类优于旧类</h3>
<p>模型倾向于时间上接近的模型有更高的敏感度，这可能是训练的过程决定的，也可能是由于再新类的训练上新类的权重要明显高于旧类，导致的某种数据不均衡的现象。</p>
<p>此外在传统的设定中，新类的数据量会大大的大于旧类</p>
<h3 id="few-shot-incremental">Few-Shot Incremental</h3>
<p>Few-Shot 的增量情景更贴切于我的场景假设，在这种假设的背景之下，增量学习也会面临一些新的困难，这个篇章中我们可能会简要的总结一些方法对抗小样本和灾难性遗忘的思路和策略。</p>
<ul>
<li>小样本的类别原型不稳定</li>
<li>容易和旧类别混淆</li>
</ul>
<p>在进行总结的同时，我们的调研方向也会有所侧重，比如基于拓扑的神经气体网络方法，我们可能暂时不那么关心（精力有限）</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220107182311.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220107182311.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220107182311.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h4 id="拓扑结构方法">拓扑结构方法</h4>
<ul>
<li>《Few-Shot Class-Incremental Learning》<sub>[10]</sub></li>
</ul>
<h4 id="sppr">SPPR</h4>
<p>《Self-Promoted Prototype Refinement for Few-Shot Class-Incremental Learning》这篇文章的主要贡献有以下的两点：</p>
<ul>
<li>提出了 RESS（随机 episode 选择策略）通过强制特征自适应于各种随机模拟的增量过程来增强特征表示的可扩展性。</li>
<li>引入了一种自提升的原型细化机制(SPPR)，利用新类样本和旧类 prototype 表示之间的关系矩阵来更新现有的 prototypical</li>
</ul>
<blockquote>
<p>RESS 实际上应该是类比 Meta Learning 提出的一种训练策略
SPPR 是本文的核心，为了保持旧类之间的依赖和新类置假你都区分度，要对新类的原型进行提炼
理论上讲 SPPR 更新的应该是模型的参数，但是在代码中我暂时没有找到对应的实现的地方</p>
</blockquote>
<p>so we drop this method which is not match our structure</p>
<h4 id="evolved-classifier">Evolved classifier</h4>
<p>由于数据量少的这个特点，我们解耦 BB 和 CLF，每次增量任务只更新分类器。</p>
<p>该文章[12]在多个数据集上实现了 SOTA，提出了 CEC（Continually Evolved Classifier），将图模型用在分类器上，它的分类器是一个无参数的 class mean classifier（听起来像 NCM）；</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220107175617.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220107175617.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220107175617.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>实际上就是在一个较优的特征空间的基础上调整我们的决策边界的一个策略，该方法引入了图注意力模型（GAT），该方法有一个特性是：</p>
<ul>
<li>增加节点而不改变其他的节点，</li>
<li>利用拓扑关系，链接关系的不变性，利于保留旧知识</li>
</ul>
<div>
$$ 
w_{new} = w_{old} + (\sum^{w_n}_k=1a_{jk}U_{w_k})
 $$
</div>
<p>使用 GAT 获得线性变换矩阵和注意力系数来更新模型的权重。</p>
<p>此外提供了一种旋转增强的新型策略，效果特别好==pseudo incremental learning==，可能和 GAT 的一些特性有关，结合 GAT 效果提升巨大，要警惕这种方法是通用的还是特异性的。最好是看看有没有原理分析。</p>
<h4 id="cebn">CEBN</h4>
<p>采用三阶段的方式来实现小样本的增量学习，根据上述的任务划分图来确定不同的实验阶段：</p>
<ol>
<li>用大量数据训练基准的分类模型，使用的就是 base class</li>
<li>学习 novel class 防止灾难性遗忘，只使用新类数据（修正 CE 考虑小样本问题）（使用参数来正则防止 BB 灾难遗忘）</li>
<li>混合数据进行训练，这个时候使用一个 balance 的数据集，比如说做多次增量的话，在最后一次使用 balance replay 即可。</li>
</ol>
<p>第二阶段的损失是这里的关键，基于 CEBN 修改 CE，为啥我看不出区别，我感觉实际上就是 CE，只是虽然只用新数据训练，但是分类器是完整的罢了，其实就是 CE：</p>
<div>
$$ 
CE_{BN}(x) = \sum_{C_N}y_iln(\frac{exp(o_i)}{\sum_{C_N} exp(o_j) + \sum_{C_B}(o_k)})
 $$
</div>
<p>正则项则通过对前后的 Backbone 进行约束得到：</p>
<div>
$$ 
L_2^{WC} = \sum||\theta_1 - \theta_2||^2
 $$
</div>
<p>最终整合起来的损失如下：</p>
<div>
$$ 
Loss = L_2^{WC} + \lambda CE_{BN}
 $$
</div>
<h2 id="references">References</h2>
<p><a href="https://github.com/xialeiliu/Awesome-Incremental-Learning" target="_blank" rel="noopener">📚Awesom Incremental Learning Collections</a>
 | <a href="https://paperswithcode.com/task/incremental-learning" target="_blank" rel="noopener">🌤️Paper w Code Incremental Learning</a>
</p>
<ol>
<li><a href="https://arxiv.org/abs/1606.09282" target="_blank" rel="noopener">Learning without Forgetting</a>
 | <a href="https://zhuanlan.zhihu.com/p/51587674" target="_blank" rel="noopener">ZHIHU</a>
 | ECCV2016</li>
<li><a href="https://arxiv.org/abs/1611.07725" target="_blank" rel="noopener">iCaRL Incremental Classifier and Representation Learning</a>
 | <a href="https://www.cnblogs.com/marsggbo/p/10321834.html" target="_blank" rel="noopener">CnBlog</a>
 ， <a href="https://zhuanlan.zhihu.com/p/51639634" target="_blank" rel="noopener">ZhiHu</a>
 | CVPR2017</li>
<li><a href="">Ene-to-End Incremental Learning</a>
 | ECCV2018</li>
<li>⭐ <a href="https://arxiv.org/abs/2004.13513" target="_blank" rel="noopener">PODNet Pooled Outputs Distillation for Small-Tasks Incremental Learning</a>
 | <a href="https://github.com/arthurdouillard/incremental_learning.pytorch" target="_blank" rel="noopener">ECCV2020</a>
 | <a href="https://blog.csdn.net/weixin_36474809/article/details/116140481" target="_blank" rel="noopener">CSDN</a>
</li>
<li><a href="">Large Sacale Incremental Learning</a>
 | CVPR2019 | <a href="https://blog.csdn.net/dhaiuda/article/details/102852694" target="_blank" rel="noopener">CSDN</a>
</li>
<li><a href="https://blog.csdn.net/dhaiuda/article/details/102850853" target="_blank" rel="noopener">Learning a Unified Classifier Incrementally via Rebalancing</a>
 | CVPR2019 |</li>
<li><a href="https://arxiv.org/pdf/1911.07053.pdf" target="_blank" rel="noopener">Maintaining discrimination and fairness in class incremental learning</a>
 | CVPR2020</li>
<li><a href="https://arxiv.org/abs/2103.17230" target="_blank" rel="noopener">Rainbow Memory: Continual Learning with a Memory of Diverse Samples</a>
 | <a href="https://github.com/clovaai/rainbow-memory" target="_blank" rel="noopener">CVPR2021</a>
 | <a href="https://blog.csdn.net/weixin_36474809/article/details/116140087" target="_blank" rel="noopener">CSDN</a>
</li>
<li><a href="https://arxiv.org/abs/2103.13885" target="_blank" rel="noopener">Supervised Contrastive Replay: Revisiting the Nearest Class Mean Classifier in Online Class-Incremental Continual Learning</a>
 | CVPR2021 | <a href="https://blog.csdn.net/weixin_36474809/article/details/116310575" target="_blank" rel="noopener">CSDN</a>
</li>
<li><a href="">Few-Shot Class-Incremental Learning</a>
 | CVPR2020 | <a href="https://blog.csdn.net/weixin_36474809/article/details/116176530" target="_blank" rel="noopener">CSDN</a>
</li>
<li><a href="https://openaccess.thecvf.com/content/CVPR2021/papers/Zhu_Self-Promoted_Prototype_Refinement_for_Few-Shot_Class-Incremental_Learning_CVPR_2021_paper.pdf" target="_blank" rel="noopener">Self-Promoted Prototype Refinement for Few-Shot Class-Incremental Learning</a>
 | <a href="https://github.com/zhukaii/SPPR" target="_blank" rel="noopener">CVPR2021</a>
 | <a href="https://blog.csdn.net/qq_40825479/article/details/122199901" target="_blank" rel="noopener">CSDN</a>
</li>
<li><a href="">Few Shot Incremental Learning with Continually Evolved Classifiers</a>
 | <a href="https://blog.csdn.net/weixin_36474809/article/details/116612960" target="_blank" rel="noopener">CVPR2021</a>
 |</li>
<li><a href="">Generalized and Incremental Few-Shot Learning by  Explicit Learning and Calibration without Forgetting</a>
 | ICCV2021 | <a href="https://blog.csdn.net/weixin_58666589/article/details/120682594" target="_blank" rel="noopener">CSDN</a>
</li>
<li><a href="https://link.zhihu.com/?target=https%3A//openaccess.thecvf.com/content/CVPR2021/html/Zhu_Prototype_Augmentation_and_Self-Supervision_for_Incremental_Learning_CVPR_2021_paper.html" target="_blank" rel="noopener">Prototype Augmentation and Self-Supervision for Incremental Learning</a>
 | <a href="https://link.zhihu.com/?target=https%3A//github.com/Impression2805/CVPR21_PASS" target="_blank" rel="noopener">CVPR2021</a>
 | <a href="https://zhuanlan.zhihu.com/p/416717749?utm_medium=social&amp;utm_oi=74269941825536" target="_blank" rel="noopener">ZHIHU</a>
</li>
<li><a href="">Contrastive Continual Learning</a>
 | ICCV2022 | CSDN</li>
</ol>
<p><strong>一些总结笔记</strong></p>
<ul>
<li><a href="https://zhuanlan.zhihu.com/p/337287727" target="_blank" rel="noopener">Classic Incremental Papers</a>
</li>
<li><a href="https://blog.csdn.net/abcdefg90876/article/details/114109237" target="_blank" rel="noopener">Background and Dilemma</a>
</li>
<li><a href="https://www.sciencedirect.com/science/article/pii/S0925231221014995" target="_blank" rel="noopener">Online Continual Learning An Empirical Survey</a>
 | 2021 | <a href="https://ripe-heliotrope-6f4.notion.site/Online-Continual-Learning-in-Image-Classification-An-Empirical-Survey-25bbcd8d3c2b492aa983a4320d1150de#a57ead60cdaf4ac5b42b8dce849266b2" target="_blank" rel="noopener">Notion</a>
 这篇综述给人的感觉比较一般把，或者可能是总结文档里没有写出比较关键的一些看法和证据。感觉不是特别推荐阅读。</li>
<li><a href="https://blog.csdn.net/weixin_36474809/article/details/116720597" target="_blank" rel="noopener">Incremental Learning in 20-21</a>
 | 下面的图也来自这篇文章</li>
</ul>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220106201641.png">
    <img alt="Fig1" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220106201641.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220106201641.png" style="display: block; margin: 0 auto;"
      alt="Fig1"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>


<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220106201645.png">
    <img alt="Fig2" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220106201645.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220106201645.png" style="display: block; margin: 0 auto;"
      alt="Fig2"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>


<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220106201649.png">
    <img alt="Fig3" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220106201649.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220106201649.png" style="display: block; margin: 0 auto;"
      alt="Fig3"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="to-be-placed-in-the-right-place">to be placed in the right place</h2>
<p>将一些新的研究先放在这里，到时候看看要组织到笔记的那一部分。</p>
<h3 id="class-incremental-learning-via-dual-augmentation">class-Incremental learning via Dual Augmentation</h3>
<p>该文章认为，类增量学习中灾难性遗忘可以被总结为两个方面带来的：特征表示上的偏差和分类器上的偏差。</p>
<ol>
<li>增量过程中如果不对特征提取器进行适应，则对新特征的提取能力不够；如果进行适应则会产生灾难性的遗忘</li>
<li>分类器如果不进行更新，会和新的特征表示不适应，而由于没有旧类的数据，就没有更新旧类的方向</li>
</ol>
<p>解决的思路是：</p>
<ul>
<li>训练的阶段做mixup来做混合类的学习，通过这种预先训练，来帮助模型得到一个较为稳定的表征。</li>
<li>分类上将历史数据的均值和方差记录下来，对模型更新的时候，通过分布信息生成语义特征维持决策边界，防止对旧类分成新类。</li>
</ul>
<p>第二部分具体细节的实现上还不是很清晰，后续可以看代码，但是目前来看不是我们需要的。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220315151105.jpg">
    <img alt="preview" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220315151105.jpg"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220315151105.jpg" style="display: block; margin: 0 auto;"
      alt="preview"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="looking-back-on-learned-experiences-for-classtask-incremental-learning">Looking back on learned experiences for class/task incremental learning</h3>
<p>主要贡献：无数据的增量学习，支持经验重放，不需要平行网络输出蒸馏监督。</p>
<p>kd使用的是最小欧拉距离：L2范数的平方作为损失。</p>
<h3 id="overcoming-catastrophic-forgetting-in-incremental-few-shot-learning-by-finding-flat-minima">Overcoming Catastrophic Forgetting in Incremental Few-Shot Learning by Finding Flat Minima</h3>
<p><a href="https://blog.csdn.net/qq_40825479/article/details/122352675" target="_blank" rel="noopener">CSDN</a>
</p>
<p>在基础模型训练阶段，企图找到一个损失的下降平坦点而不是简单的一个极小值，平坦极小值的模型的鲁棒性能会比普通的模型优异一些，具体对于平坦点的定义可以参见下面的这张图：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220315161428">
    <img alt="img" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220315161428"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20220315161428" style="display: block; margin: 0 auto;"
      alt="img"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>这种平坦点的研究，实际上和NotZeroLoss的设定具有相当的相似性，帮助模型学习到一个更加稳定的解，而该解在后续进行增量学习的过程中，会减少对应的灾难性遗忘的现象。</p>
<h3 id="distilling-causal-effect-of-data-in-class-incremental-learning">Distilling causal effect of data in class-incremental learning</h3>
<p>也是通过因果分析来筹建分类结果，通过TDE的方式消除类别偏差，这一部分实际上和我们的Causal模块和统计均值模块应该是起到了相同的作用，这里暂时不深入进行解读。</p>
<p>==the two below== is important for our research:</p>
<h3 id="do-not-forget-to-attend-to-uncertainty-while-mitigating-catastrophic-forgetting">Do not Forget to Attend to Uncertainty while Mitigating Catastrophic Forgetting</h3>
<p><a href="https://arxiv.org/pdf/2102.01906.pdf" target="_blank" rel="noopener">Papers</a>
 using attention and the bayes formula to calculate the Uncertainty or something else.</p>
<h3 id="continual-learning-in-the-teacher-student-setup-impact-of-task-similarity">Continual Learning in the Teacher-Student Setup: Impact of Task Similarity</h3>
<p><a href="https://www.ijcai.org/proceedings/2021/0137.pdf" target="_blank" rel="noopener">Papers</a>
 do a lot for the loss, which we should pay attention for it.</p>
]]></content:encoded>
    </item>
    <item>
      <title>WYZ-IL-Collection</title>
      <link>https://aikenh.cn/posts/il-wyz/</link>
      <pubDate>Mon, 03 Jan 2022 10:41:56 +0000</pubDate>
      <guid>https://aikenh.cn/posts/il-wyz/</guid>
      <description>&lt;p&gt;: hammer: 王耀智&lt;/p&gt;
&lt;h2 id=&#34;regularization-系列方法&#34;&gt;Regularization 系列方法&lt;/h2&gt;
&lt;p&gt;这类方法旨在添加一些正则化损失来解决 &lt;code&gt;catastrophic forgetting&lt;/code&gt; 的问题。&lt;/p&gt;
&lt;h3 id=&#34;weight-regularization&#34;&gt;Weight Regularization&lt;/h3&gt;
&lt;p&gt;这类方法一般是对网络中每个参数的重要性进行评估，根据每个参数的重要性和梯度信息更新参数。&lt;/p&gt;
&lt;p&gt;典型的文章为 &lt;a href=&#34;https://www.pnas.org/content/pnas/114/13/3521.full.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;EWC&lt;/a&gt;
 .&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;PS: 这类文章我也没有读过。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;data-regularization&#34;&gt;Data Regularization&lt;/h3&gt;
&lt;p&gt;这类方法专注于记住特征表示，通常是结合 Hinton 的知识蒸馏损失函数使得模型记住旧类别的知识，解决 catastrophic forgetting。&lt;/p&gt;
&lt;p&gt;推荐以下几篇文章：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LwF&lt;/code&gt;(Learning without forgetting)，这篇文章在我看来是增量学习的开山之作，第一次给增量学习找到了一个比较好的方向，也是第一次将知识蒸馏应用到增量学习上；&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://arxiv.org/abs/2004.13513&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;PODNet CVPR2020&lt;/a&gt;
 ，这篇文章最大的贡献在我看来是设计了一个全新的蒸馏损失函数，最终结果也是达到了当时的sota，甚至目前也是几个榜单的sota。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;rehearsal-系列方法&#34;&gt;Rehearsal 系列方法&lt;/h2&gt;
&lt;p&gt;这类方法主要的想法是使用一些旧类别的数据，在新类别到来时使用新旧数据一起训练模型，根据旧类别数据的真假分为以下两种方法。&lt;/p&gt;
&lt;h3 id=&#34;pseudo-rehearsal&#34;&gt;Pseudo rehearsal&lt;/h3&gt;
&lt;p&gt;这类方法通常是在学习旧类别的同时，训练一个生成模型，可以生成旧的类别数据，在新类别数据到来时，生成相当数量的旧类别数据，一起训练新模型。&lt;/p&gt;
&lt;p&gt;这里推荐一篇文章：Continual learning with deep generative replay。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;PS：这个小类别的论文我也没有太关注，个人不是很推荐这类方法。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;save-real-data&#34;&gt;Save real data&lt;/h3&gt;
&lt;p&gt;这类方法是开辟一个内存空间，空间中保存旧类别的少部分训练数据，在新类别到来时，使用内存空间的数据与新数据共同学习，按照对空间的使用方法不同可分为：&lt;/p&gt;
&lt;h4 id=&#34;exemplar-rehearsal&#34;&gt;Exemplar Rehearsal&lt;/h4&gt;
&lt;p&gt;这类方法是将新旧数据混合，共同作为训练数据，一起训练模型，使得模型能够保持旧类别的知识。&lt;/p&gt;
&lt;p&gt;但是在训练过程中新旧数据的类别数量是不均衡的，这也催生了我下面会说到的一大类解决方法。&lt;/p&gt;
&lt;p&gt;这种方法推荐的论文是 &lt;code&gt;iCaRL&lt;/code&gt;，这篇论文是 exemplar rehearsal 的开山之作，第一次提出了内存空间这个概念，也提出了一个非常有效的内存选择策略(herb)，并且也是第一个使用特征作为分类依据的方法，我个人认为是继 LwF 之后又一个将 IL 推到一个新的高度的方法。&lt;/p&gt;
&lt;h4 id=&#34;gradient-rectification&#34;&gt;Gradient Rectification&lt;/h4&gt;
&lt;p&gt;这类方法我称之为 Gradient Rectification，其主要思路是模型每次更新的梯度由 shared gradient 和 task-specific gradient 组成。分别代表所有类别的共性信息和某一个类别的特性信息，在新类别学习时借助内存空间中的数据获得旧类别的两项梯度，在更新时对梯度进行修正，力求做到不增加共享梯度代表的损失，尽量减少类别特定梯度代表的损失。&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>: hammer: 王耀智</p>
<h2 id="regularization-系列方法">Regularization 系列方法</h2>
<p>这类方法旨在添加一些正则化损失来解决 <code>catastrophic forgetting</code> 的问题。</p>
<h3 id="weight-regularization">Weight Regularization</h3>
<p>这类方法一般是对网络中每个参数的重要性进行评估，根据每个参数的重要性和梯度信息更新参数。</p>
<p>典型的文章为 <a href="https://www.pnas.org/content/pnas/114/13/3521.full.pdf" target="_blank" rel="noopener">EWC</a>
 .</p>
<blockquote>
<p>PS: 这类文章我也没有读过。</p>
</blockquote>
<h3 id="data-regularization">Data Regularization</h3>
<p>这类方法专注于记住特征表示，通常是结合 Hinton 的知识蒸馏损失函数使得模型记住旧类别的知识，解决 catastrophic forgetting。</p>
<p>推荐以下几篇文章：</p>
<ul>
<li><code>LwF</code>(Learning without forgetting)，这篇文章在我看来是增量学习的开山之作，第一次给增量学习找到了一个比较好的方向，也是第一次将知识蒸馏应用到增量学习上；</li>
<li><a href="https://arxiv.org/abs/2004.13513" target="_blank" rel="noopener">PODNet CVPR2020</a>
 ，这篇文章最大的贡献在我看来是设计了一个全新的蒸馏损失函数，最终结果也是达到了当时的sota，甚至目前也是几个榜单的sota。</li>
</ul>
<h2 id="rehearsal-系列方法">Rehearsal 系列方法</h2>
<p>这类方法主要的想法是使用一些旧类别的数据，在新类别到来时使用新旧数据一起训练模型，根据旧类别数据的真假分为以下两种方法。</p>
<h3 id="pseudo-rehearsal">Pseudo rehearsal</h3>
<p>这类方法通常是在学习旧类别的同时，训练一个生成模型，可以生成旧的类别数据，在新类别数据到来时，生成相当数量的旧类别数据，一起训练新模型。</p>
<p>这里推荐一篇文章：Continual learning with deep generative replay。</p>
<blockquote>
<p>PS：这个小类别的论文我也没有太关注，个人不是很推荐这类方法。</p>
</blockquote>
<h3 id="save-real-data">Save real data</h3>
<p>这类方法是开辟一个内存空间，空间中保存旧类别的少部分训练数据，在新类别到来时，使用内存空间的数据与新数据共同学习，按照对空间的使用方法不同可分为：</p>
<h4 id="exemplar-rehearsal">Exemplar Rehearsal</h4>
<p>这类方法是将新旧数据混合，共同作为训练数据，一起训练模型，使得模型能够保持旧类别的知识。</p>
<p>但是在训练过程中新旧数据的类别数量是不均衡的，这也催生了我下面会说到的一大类解决方法。</p>
<p>这种方法推荐的论文是 <code>iCaRL</code>，这篇论文是 exemplar rehearsal 的开山之作，第一次提出了内存空间这个概念，也提出了一个非常有效的内存选择策略(herb)，并且也是第一个使用特征作为分类依据的方法，我个人认为是继 LwF 之后又一个将 IL 推到一个新的高度的方法。</p>
<h4 id="gradient-rectification">Gradient Rectification</h4>
<p>这类方法我称之为 Gradient Rectification，其主要思路是模型每次更新的梯度由 shared gradient 和 task-specific gradient 组成。分别代表所有类别的共性信息和某一个类别的特性信息，在新类别学习时借助内存空间中的数据获得旧类别的两项梯度，在更新时对梯度进行修正，力求做到不增加共享梯度代表的损失，尽量减少类别特定梯度代表的损失。</p>
<p>这类方法的论文推荐是 CVPR 2021 的 <code>Layerwise optimization by gradient decomposition for continual learning</code>，还有其前身作 <code>GEM</code>。</p>
<h2 id="struture-base-methods">Struture Base Methods</h2>
<p>这类方法旨在设计一些新的结构或者更改结构以适应 IL 的实验设置，具体也分为两类：</p>
<h3 id="special-architecture">Special Architecture</h3>
<p>这类方法设计一些特殊的模型或者拓展模型来适应 IL。</p>
<p>推荐几篇文章：</p>
<ul>
<li><code>Lifelong learning with dynamically expandable network.</code></li>
<li><a href="https://arxiv.org/pdf/2010.05063.pdf" target="_blank" rel="noopener"><code>Adaptive Aggregation Networks for Class-Incremental Learning</code></a>
</li>
</ul>
<h3 id="violent-stacking">Violent Stacking</h3>
<p>这类方法是每次 task 训练一个特征提取器，然后将其与之前的堆叠，最后进行剪枝操作，减少模型参数。</p>
<p>这类方法目前只有一篇文章，CVPR 2021 的 <code>DER</code>，也是达到了部分 sota。</p>
<h2 id="classifier-rectification">Classifier Rectification</h2>
<p>这类方法很大程度上是为了解决上面提到的数据不均衡提出的，主要是对训练完成后的模型的 FC 层进行修正。</p>
<p>这类方法的思路通常比较简单，但是非常有效。</p>
<p>推荐以下几篇文章：</p>
<ul>
<li><code>BiC</code>: Large scale incremental learning</li>
<li><code>Maintaining discrimination and fairness in class incremental learning</code></li>
</ul>
<h2 id="others">Others</h2>
<h3 id="combine-ssl">Combine SSL</h3>
<h3 id="combine-meta-learning">Combine Meta-learning</h3>
<h3 id="define-new-problemfew-shot-il">Define New Problem(Few-shot IL)</h3>
<h3 id="application-in-other-tasks-like-object-detection">Application in other tasks, like object detection</h3>
]]></content:encoded>
    </item>
    <item>
      <title>LT Collection</title>
      <link>https://aikenh.cn/posts/lt-collection/</link>
      <pubDate>Wed, 22 Dec 2021 14:36:16 +0000</pubDate>
      <guid>https://aikenh.cn/posts/lt-collection/</guid>
      <description>Long-Tailed Learning Colooection</description>
      <content:encoded><![CDATA[<h1 id="lt-collections">LT-Collections</h1>
<p>@AikenHong 2021</p>
<p><a href="https://github.com/mitming/OpenLT" target="_blank" rel="noopener">Code of must of those methods</a>

We will analysis those tricks on LT situation, and Analysis why it works.
在进行LT矫正的任务中，有几种常见的trick在各种模型中被使用，我们会对这几种不同的trick进行介绍和分析。</p>
<p>其实在数据量少这一方面LT和Few-Shot是有一定的OverLap的,可以参考以下那边的思路perhaps</p>
<h2 id="introduction">Introduction</h2>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211217165531.png">
    <img alt="LT" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211217165531.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211217165531.png" style="display: block; margin: 0 auto;"
      alt="LT"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>通常情况下这种严重的类别不平衡问题会使得模型严重过拟合于头部，而在尾部欠拟合</p>
<p>首先介绍 <a href="https://zhuanlan.zhihu.com/p/416315017" target="_blank" rel="noopener">bag of tricks</a>
 这篇论文中总结了一些常用的Trick，并组合出了最佳的一套trick</p>
<p>经过该文实验总结，Trick组合应该是<sub>[1]`</sub>：</p>
<ul>
<li>在前几个epoch应用input mixup数据增强，然后后面fine-tuning;</li>
<li>(基于CAM的)重采样来重新训练分类器;</li>
</ul>
<p>实际上就是MixUp + Two-Stage的策略，后续对<strong>Mix-up</strong>这个策略带来的作用要进行补充了解一下</p>
<h2 id="rebalance">Rebalance</h2>
<p>对于ReBalance的方法，实际上就是从 <code>data</code>和 <code>update</code>两个角度来缓解Unbalance本身，通过从数据量上达到重新均衡，或者基于Loss使得bp过程中赋予Tail更高的权重来达到优化过程的平衡。</p>
<p>前者称为rebalance，后者则为reweight.</p>
<h3 id="reweighting">reweighting</h3>
<p>这一部分在实际设计上的体现主要是通过对Loss的重新构造而成，通过对Loss的构造来实现区分的BP权重.</p>
<ol>
<li>代价敏感softmax交叉熵损失CS_CE: 在ce前乘最小训练图像数目与每个类别图像数目的比值，相当于更注重少类样本</li>
</ol>
<div>
$$ 
    \mathcal{L}_{CS\_CE}(\mathbf{z}, c)=-\frac{n_{\min }}{n_{c}} \log \left(\frac{\exp \left(z_{c}\right)}{\sum_{i=1}^{C} \exp \left(z_{i}\right)}\right)
    $$
</div>
<ol start="2">
<li>Focal Loss：设置 $\alpha$ 和 $\beta$ 来控制少数类和难分类别对损失的贡献：</li>
</ol>
<div>
$$ \mathcal{L}_{\text {Focal }}(\mathbf{z}, c)=-\sum_{i=1}^{C}\left(1-p_{i}^{t}\right)^{\gamma} \log \left(p_{i}^{t}\right) $$
</div>
<ol start="3">
<li>类别平衡损失：就是在基本的损失（CE，FOCAL）前加入一个衡量权重，其中 $\beta$ 是一个超参数，来衡量有效的信息</li>
</ol>
<div>
$$ \mathcal{L}_{CB\_Focal}(\mathbf{z}, c)=-\frac{1-\beta}{1-\beta^{n_{c}}} \sum_{i=1}^{C}\left(1-p_{i}^{t}\right)^{\gamma} \log \left(p_{i}^{t}\right) $$
</div>
<ol start="4">
<li>Logit Abjustment<sub>[3]</sub>:</li>
</ol>
<div>
$$ \ell(y, f(x))=\alpha_{y} \cdot \log \left[1+\sum_{y^{\prime} \neq y} e^{\Delta_{y y^{\prime}}} \cdot e^{\left(f_{y^{\prime}}(x)-f_{y}(x)\right)}\right] $$
</div>
<h3 id="rebalance-1">rebalance</h3>
<p>实际上就是对少类或者多类的数据重新做均衡，方法的本质差别一般都不是特别大</p>
<ol>
<li><strong>随机过采样</strong>：随即重复少数类别的样本来使得样本均衡</li>
<li><strong>随机降采样</strong>：随机删除多数类别的样本使得样本均衡</li>
<li><strong>样本平衡采样</strong>：应该值得就是1-2 IB-Sampling</li>
<li><strong>类别平均采样</strong>: 对类别进行统一采样，每个类别被采样的概率都一样(Q=0)，然后从每个类别中有放回的随机采样实例，从而构建平衡的数据集</li>
</ol>
<div>
$$ p_j = \frac{n_j^q}{\sum_{i=1}^C n_i^q} $$
</div>
<ol start="5">
<li><strong>平方根采样</strong>(Q=0.5)</li>
<li><strong>逐步平衡采样</strong>：先对多个epoch进行实例平衡采样（上式q=1，也就是没有任何平衡操作的采样），然后再剩下的epoches中进行类别平衡采样。这种采样方式需要设置一个超参数来调整从哪一个epoch开始变换采样方式。也可以使用更软的阈值，即随着epoch的增加来逐渐调整实例平衡采样（IB）和类别平衡采样所占的比例，如下面公式所示。</li>
</ol>
<div>
$$ 
P_j^{PB} (t) = (1-\frac{t}{T})P_j^{IB} + \frac{t}{T}P_j^{CB}
 $$
</div>
<h2 id="two-stage">two-stage</h2>
<p>在Unbalanced的Data上Pretrain一个特征提取器，然后再rebalance（IB，CB）的数据集上对Classifier进行重新训练（调整），（and | or）对齐，校准（disalign，causal）来提升LT的性能的方法</p>
<h3 id="motivation">motivation</h3>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211217165813.png">
    <img alt="rebalance" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211217165813.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211217165813.png" style="display: block; margin: 0 auto;"
      alt="rebalance"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>但是这些rebalance的方法通常会带来以下两个问题<sub>[2]</sub>：</p>
<ul>
<li>rebalance之后分类器会倾向于分类正确的尾部样本，导致对于头部有一定的bad influence（欠拟合），对尾部过拟合</li>
<li>rebalance方法会显著的促进分类器的学习，但是会损害深度特征的表示能力，如上图所示，分类器学到的分界面更好，但是特征的表示却更加的松散了</li>
</ul>
<blockquote>
<p>我认为rebalance的策略确实会使得Clf学的更好的分界面，减少偏向性，但是不至于在尾部过拟合，这一部分分析最重要的应该是rebalance对于特征空间的Bad Influence，这可能就是Two Stage的来源。</p>
</blockquote>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211217172128.png">
    <img alt="Absl" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211217172128.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211217172128.png" style="display: block; margin: 0 auto;"
      alt="Absl"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>于是作者为其设计了一些消融实验：CE指的是长尾，RW，RS指的是使用的rebalance的数据。</p>
<p>可以发现在Backbone上使用Unbalance的数据而在Clf上使用Resampler的数据效果是最好的，这种two-stage的解耦两阶段的训练策略展现了一个有希望的结果。</p>
<blockquote>
<p>这种两阶段的方式，我认为在第二阶段的时候也要对特征进行微调来适应当前的分布，不过很多的方法都是直接只对分类器进行调整，我们可以对两种方式进行测试</p>
</blockquote>
<p><em>下图显示了fix-two-stage和baseline对比</em><sub>[5]</sub></p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211218155958.png">
    <img alt="two-stage" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211218155958.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211218155958.png" style="display: block; margin: 0 auto;"
      alt="two-stage"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><em>下图展示了理想的two-stage结果与显示方法之间的距离</em><sub>[5]</sub>
cls-bound是再fix特征后，用完全均衡的数据集训练分类器得到的结果，由此带入第二张图的绿色的线，可以知道，现有长尾方法的性能瓶颈（未使用two-stage），仍然在特征空间中的有偏差的决策边界。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211218161858.png">
    <img alt="ideal-real" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211218161858.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211218161858.png" style="display: block; margin: 0 auto;"
      alt="ideal-real"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>基于这些分析,我们认为，在得到一个强有力的特征表示后，我们可以将问题归化到分类器上，基于这点假设，我们可以结合我们的自监督模块来对该方法进行归化。</p>
<h3 id="bbn-structure">BBN structure</h3>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211218124356.png">
    <img alt="BBN" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211218124356.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211218124356.png" style="display: block; margin: 0 auto;"
      alt="BBN"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>

Share Weight of Backbone，Using diff dataset to get diff feature. Then we using $\alpha$ to Combine the logits and calculate the loss.</p>
<div>
$$ 
z = \alpha * W_c^T * f_c + (1-\alpha) * W_\gamma^T * f_\gamma
 $$
</div>
<div>
$$ 
L = \alpha * l(softmax(z),y_c) + (1-\alpha) *l(softmax(z),y_\gamma)
 $$
</div>
<p>在上述的流程图中W代表的是两个不一样的数据优化器，基于这样的设置最终就能区分两部分的优化。</p>
<blockquote>
<p>但是这个方法为我们带来的最大的启发还是在于区分两阶段中学习的重点，backbone需要在一个unblance的条件下学习一个更为通用的表征，而Cls需要矫正偏差。不平衡的情况下可能能学到一个很好的通用表征，这一点就是我们使用自监督的一个重要原因。</p>
</blockquote>
<h3 id="decoupling">Decoupling</h3>
<p>==Train BB and Fixed then Train CLF==
此外坐着发现全连接的weight和norm和对应类别的样本数正相关，所以在第二部最后将分类器改为归一化的分类器，文中的两种设计是：</p>
<ol>
<li>$\overline{W_i}=\frac{w_i}{\lVert W_i \rVert^T}$</li>
<li>$\overline{W_i}=\frac{w_i}{f_i}$</li>
</ol>
<p>其中2利用fixed第一步分类权重 $w_i$ ,对每个类学习了一个加权参数 $f_i$</p>
<h3 id="better-calibration">better-calibration</h3>
<p>但是这种两阶段的方式也不是没有代价的，他会带来比较严重的<strong>校准错误</strong>(Calibration)，也就是我们预测的概率和实际的相似度之间的一致性。</p>
<p>（BTW评估校准错误的指标 $ECE=\sum_{b=1}^B\frac{|S_b|}{N} |acc(S_b) - conf(S_b)|$ ，将数据分为b组，S_b是落入b区间的样本集合)</p>
<p>本文主要测试了MixUP在两阶段训练中的作用，以及提出了：</p>
<ol>
<li>标签感知平滑损失，实际上就是cb_ce的半泛化形式：</li>
</ol>
<div>
$$ \begin{gathered}
l(\boldsymbol{q}, \boldsymbol{p})=-\sum_{i=1}^{K} \boldsymbol{q}_{i} \log \boldsymbol{p}_{i} \\
\boldsymbol{q}_{i}= \begin{cases}1-\epsilon_{y}=1-f\left(N_{y}\right), & i=y \\
\frac{\epsilon_{y}}{K-1}=\frac{f\left(N_{y}\right)}{K-1}, & \text { Otherwise }\end{cases}
\end{gathered} $$
</div>
<p>$\epsilon_y$ 是y(gt)的一个小平滑因子,数目与类别的样本数有关，并提出了几种函数形式，来优化这个损失
2. BN的移位学习，由于两阶段的数据集不一致，所以normalize的参数是需要学习变化的（均值和方差）</p>
<p>具体的数学分析和推导，后续根据论文理解了再来补充</p>
<h3 id="disalign">DisAlign</h3>
<p>基于上述对于方法的分析，该文章着重于对于分类器进行校准，具体的思路是基于利于平衡预测的类别分布来对分类器的输出进行匹配，矫正；简单的说利用类别先验和输入数据学习类别的决策边界。
具体由两部分构成(重构预测的概率输出，建立理想分布，使用KL散度计算损失)</p>
<ol>
<li>自适应配准函数</li>
</ol>
<div>
$$ \begin{gathered}
s_{j}=\alpha_{j} \cdot z_{j}^{o}+\beta_{j}, \quad \forall j \in \mathcal{C} \\
\hat{z}_{j}=\sigma(\mathbf{x}) \cdot s_{j}+(1-\sigma(\mathbf{x})) \cdot z_{j}^{o} \\
=\left(1+\sigma(\mathbf{x}) \alpha_{j}\right) \cdot z_{j}^{o}+\sigma(\mathbf{x}) \cdot \beta_{j} \\
p_{m}(y=j \mid \mathbf{x})=\frac{\exp \left(\hat{z}_{j}\right)}{\sum_{k=1}^{C} \exp \left(\hat{z}_{k}\right)}
\end{gathered} $$
</div>
<ol start="2">
<li>广义重加权校准
理想的分布的计算方法如下，定义说的不是很好，最好还是参考一下代码</li>
</ol>
<div>
$$ \begin{gathered}
p_{r}\left(y=c \mid \mathbf{x}_{i}\right)=w_{c} \cdot \delta_{c}\left(y_{i}\right), \quad \forall c \in \mathcal{C} \\
w_{c}=\frac{\left(1 / r_{c}\right)^{\rho}}{\sum_{k=1}^{K}\left(1 / r_{k}\right)^{\rho}}, \quad \forall c \in \mathcal{C}
\end{gathered} $$
</div>
<p>最终的损失计算方程如下：</p>
<div>
$$ 
\begin{aligned}
\mathcal{L} &=\mathbb{E}_{\mathcal{D}_{t r}}\left[\mathcal{K} \mathcal{L}\left(p_{r}(y \mid \mathbf{x}) \| p_{m}(y \mid \mathbf{x})\right)\right] \\
& \approx-\frac{1}{N} \sum_{i=1}^{N}\left[\sum_{y \in \mathcal{C}} p_{r}\left(y \mid \mathbf{x}_{i}\right) \log \left(p_{m}\left(y \mid \mathbf{x}_{i}\right)\right)\right]+C
\end{aligned}
 $$
</div>
<p>==训练的具体策略==
1）在第一阶段，在不平衡数据集上使用实例平衡 ( instance-balanced ) 采样策略实现特征提取器和原始分类头的联合学习。此时由于不平衡的数据分布，学习到的原始分类头是严重有偏的。</p>
<p>2）在第二阶段，我们在特征提取器参数固定不变的情况下关注分类头以调整决策边界，引入了自适应配准函数 ( adaptive calibration function ) 和广义重加权 ( generalized re-weight ) 策略来配准各类概率。</p>
<h2 id="caucal-analysis">Caucal Analysis</h2>
<p>基于two-stage的这种现象，然后分析机器和人学习的区别，认为带来偏差的元凶在于Optim优化算法，为此，该文章构建因果图，从而去除在模型更新过程中由动量带来的偏差效应。</p>
<center>"keep good and remove bad momentum"<sub>[7]</sub></center>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211218172020.png">
    <img alt="causal" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211218172020.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211218172020.png" style="display: block; margin: 0 auto;"
      alt="causal"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>$v_t = \mu · v_{t-1} + g_t$ , $\theta = \theta_{t-1} - lr · v_t$</p>
<p>要调用这个方法的话，我们就需要</p>
<ol>
<li>将训练的CLF修改成Multi-Head并Normlize，参考Decouple.</li>
<li>训练过程中统计移动平局特征 $\overline{x}$ ，将其单位方向看成头部倾向.</li>
<li>测试的过程中修正logits即可</li>
</ol>
<p>具体公式参考对应的解析和代码实现;</p>
<p>和自监督结合的话，只需要在微调的阶段进行统计和修正即可，毕竟是一个一阶段的方式。</p>
<h2 id="contrastive">Contrastive</h2>
<p>这一部分考虑一些和对比学习，或者说自监督学习耦合的方法来进行分析。</p>
<p>为何将这两者放到同一个章节中？
因为这两者企图从表征的层面，为LT任务，带来增益，得到一个可分的特征空间基于良好的特征表达，进而解耦的来训练一个更好的CLF。</p>
<blockquote>
<p>如果我们假设我们能得到一个高维线性可分的特征空间，对于长尾的样本带来的训练偏差（决策面偏差）是否可以通过对于特定类别的Margin-Like的Loss设置，达到一个类似Balance的效果，这一点上实际上可能和Align和校正的思想有点相似。但是我们是为了让分类器空间中的分界面在小样本的束缚下变得更加的合理。</p>
</blockquote>
<p>从分界面的角度看LT的情况：（上面是普通CE，下面是Contrastive Learning）

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211219145815.png">
    <img alt="CL" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211219145815.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211219145815.png" style="display: block; margin: 0 auto;"
      alt="CL"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>

在数据量出现较大的差异的情况下，由于蓝色的数目更多更杂，所以实际上分界面可能会沿着蓝色数据的边界做切分（overfit），在这种Class-Level的过拟合下，就会导致对于少数类别的分类结果很差。</p>
<p>而下方的对比学习就是一样的解决方案，他试图将同一类的数据聚拢在一起，将不同类的距离尽可能的拉远，这样会使得在空间中的决策面更加的鲁棒也已于区分，虽然可能会一定程度上减少蓝色的表现，但是红色的表现会因此大大的提升。</p>
<h3 id="hybird-contrastive">hybird contrastive</h3>
<p>该文章<sub>[9]</sub>的基本架构上实际上参考的就是BBN的epoch-params在two-stage中集成 supervised contrasive Loss，具体框架可以看下面这图：

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211219150447.png">
    <img alt="hybird-contrastive learning for lt" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211219150447.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211219150447.png" style="display: block; margin: 0 auto;"
      alt="hybird-contrastive learning for lt"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>

他的设计思想很容易从这张图中领会，损失函数的表达显然如下</p>
<div>
$$ 
L_{hybird} = \alpha · L_{SCL}(B_{SC}) + (1-\alpha) · L_{ce}(B_{CE})
 $$
</div>
<p>在这里要注意SC和自监督中使用的区别在于，自监督学习的过程中没有标签，所以只能将自己作为Positive，而在SC的时候，同类的样本之间应该都作为Positive</p>
<div>
$$ 
\mathcal{L}_{S C L}\left(\mathbf{z}_{i}\right)=\frac{-1}{\left|\left\{\mathbf{z}_{i}^{+}\right\}\right|} \sum_{\mathbf{z}_{j} \in\left\{\mathbf{z}_{i}^{+}\right\}} \log \frac{\exp \left(\mathbf{z}_{i} \cdot \mathbf{z}_{j} / \tau\right)}{\sum_{\mathbf{z}_{k}, k \neq i} \exp \left(\mathbf{z}_{i} \cdot \mathbf{z}_{k} / \tau\right)}
 $$
</div>
<p>鉴于SC的计算复杂度要和整个Epoch的数据进行对比，需要大量的显存空间，在这方面作者将其改进为PSC，其实也就是将每个class计算一个prototype，然后基于原型去计算这个相似性损失</p>
<div>
$$ 
\mathcal{L}_{P S C}\left(\mathbf{z}_{i}\right)=-\log \frac{\exp \left(\mathbf{z}_{i} \cdot \mathbf{p}_{y_{i}} / \tau\right)}{\sum_{j=1, j \neq y_{i}}^{C} \exp \left(\mathbf{z}_{i} \cdot \mathbf{p}_{j} / \tau\right)}
 $$
</div>
<p>在这里这个Prototypical需要正则化到单位元中，这样能快速计算相似性损失，也不会需要大量的现存。</p>
<blockquote>
<p>可以参考的点主要就在于损失的设计和框架上的这种分epoch机制了，但是基于自监督的方式的话，可能不是很用的上这一点，但是我们可以考虑怎么结合这个loss去做对应的分类器。</p>
</blockquote>
<h3 id="the-value-of-labels">The value of labels</h3>
<p>这一篇文章是将自监督学习和半监督学习应用到长尾分布的问题上，文章对应的仓库中可以get预训练模型和很多对应的数据，同时验证了下面两种策略都可以大大提升模型的效果，包括和之前的各种策略进行耦合。</p>
<ul>
<li>半监督：利用更多的无标注数据</li>
<li>自监督：不利用任何其他数据，使用长尾分布的数据进行自监督训练</li>
</ul>
<blockquote>
<p>后续的实验过程中我可能也会遵循该设计，或者使用的是全数据的自监督预训练。</p>
</blockquote>
<p>考虑尾部标签本身的意义，想要利用尾部的标签信息，又不受偏差的影响，实际上就是使用自监督进行预训练，然后后面使用各种方法兼容的一个策略。

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211219155744.png">
    <img alt="Self-Supervised" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211219155744.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211219155744.png" style="display: block; margin: 0 auto;"
      alt="Self-Supervised"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="mixup-in-lt">MixUp in LT</h2>
<p>将MixUP应用在LT中，试图&quot;以使其具有更高的泛化性，以及降低模型本身的置信度&quot;<sub>[4]</sub>, 经过实验表明，仅在Stage1使用MixUP，在Stage2的第二阶段使用几个epoch的Mixup的效果可能会更好。</p>
<p>在这里可能也要考虑一下CutMix方法</p>
<h2 id="conclusion">Conclusion</h2>
<h3 id="实验结果汇总">实验结果汇总</h3>
<p>基于BackBone对这些方法的实验结果( $Top1 Acc$ )进行汇总，作为我们后续研究的参照：在进行实验的时候，我们需要首先调整好BenchMark，基于Benchmark做的改进才能和对应的方法进行对比。</p>
<p><strong>整理原则</strong>：</p>
<ol>
<li>对应的论文则由该论文本身为主，后续和LT的仓库进行对比分析；</li>
<li>最主要需要对比的应该是ce情况下的指标，这是我们最重要的，当这个指标对齐后，我们就可以和这些方法同台竞技了。</li>
</ol>
<table>
  <thead>
      <tr>
          <th>Dataset</th>
          <th style="text-align: center">-&gt;</th>
          <th style="text-align: center">LT-Cifar-100</th>
          <th style="text-align: center">&lt;-</th>
          <th style="text-align: center">-&gt;</th>
          <th style="text-align: center">LT-CIfar10</th>
          <th style="text-align: center">&lt;-</th>
          <th>Backbone</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Factor(Exp)</td>
          <td style="text-align: center">100</td>
          <td style="text-align: center">50</td>
          <td style="text-align: center">10</td>
          <td style="text-align: center">100</td>
          <td style="text-align: center">50</td>
          <td style="text-align: center">10</td>
          <td>ResNet32</td>
      </tr>
      <tr>
          <td>RESULT</td>
          <td style="text-align: center">-</td>
          <td style="text-align: center">-</td>
          <td style="text-align: center">-</td>
          <td style="text-align: center">-</td>
          <td style="text-align: center">-</td>
          <td style="text-align: center">-</td>
          <td></td>
      </tr>
      <tr>
          <td>CE</td>
          <td style="text-align: center">38.32</td>
          <td style="text-align: center">43.85</td>
          <td style="text-align: center">55.71</td>
          <td style="text-align: center">70.36</td>
          <td style="text-align: center">74.81</td>
          <td style="text-align: center">86.39</td>
          <td>-</td>
      </tr>
      <tr>
          <td>Focal Loss</td>
          <td style="text-align: center">38.4</td>
          <td style="text-align: center">44.3</td>
          <td style="text-align: center">56.8</td>
          <td style="text-align: center">70.4</td>
          <td style="text-align: center">76.7</td>
          <td style="text-align: center">86.7</td>
          <td>-</td>
      </tr>
      <tr>
          <td>MixUp</td>
          <td style="text-align: center">39.5</td>
          <td style="text-align: center">45.0</td>
          <td style="text-align: center">58.0</td>
          <td style="text-align: center">73.1</td>
          <td style="text-align: center">77.8</td>
          <td style="text-align: center">87.1</td>
          <td>-</td>
      </tr>
      <tr>
          <td>CB Loss</td>
          <td style="text-align: center">39.6</td>
          <td style="text-align: center">45.2</td>
          <td style="text-align: center">58.0</td>
          <td style="text-align: center">74.6</td>
          <td style="text-align: center">79.3</td>
          <td style="text-align: center">87.1</td>
          <td>-</td>
      </tr>
      <tr>
          <td>BAGS-After</td>
          <td style="text-align: center">47.83</td>
          <td style="text-align: center">51.69</td>
          <td style="text-align: center">-</td>
          <td style="text-align: center">73.59</td>
          <td style="text-align: center">79.03</td>
          <td style="text-align: center">-</td>
          <td>-</td>
      </tr>
      <tr>
          <td>SSL-Uniform</td>
          <td style="text-align: center">40.40</td>
          <td style="text-align: center">45.04</td>
          <td style="text-align: center">57.07</td>
          <td style="text-align: center">73.50</td>
          <td style="text-align: center">78.20</td>
          <td style="text-align: center">87.72</td>
          <td></td>
      </tr>
      <tr>
          <td>SSL-Balanced</td>
          <td style="text-align: center">43.06</td>
          <td style="text-align: center">47.09</td>
          <td style="text-align: center">58.06</td>
          <td style="text-align: center">76.53</td>
          <td style="text-align: center">80.4</td>
          <td style="text-align: center">87.72</td>
          <td></td>
      </tr>
      <tr>
          <td>LDAM</td>
          <td style="text-align: center">42.0</td>
          <td style="text-align: center">46.6</td>
          <td style="text-align: center">58.7</td>
          <td style="text-align: center">77.0</td>
          <td style="text-align: center">81.0</td>
          <td style="text-align: center">88.2</td>
          <td>-</td>
      </tr>
      <tr>
          <td>BBN</td>
          <td style="text-align: center">42.56</td>
          <td style="text-align: center">47.07</td>
          <td style="text-align: center">59.12</td>
          <td style="text-align: center">79.82</td>
          <td style="text-align: center">82.18</td>
          <td style="text-align: center">88.32</td>
          <td>-</td>
      </tr>
      <tr>
          <td>Causal</td>
          <td style="text-align: center">44.1</td>
          <td style="text-align: center">50.3</td>
          <td style="text-align: center">59.6</td>
          <td style="text-align: center">80.6</td>
          <td style="text-align: center">83.6</td>
          <td style="text-align: center">88.5</td>
          <td>-</td>
      </tr>
  </tbody>
</table>
<h2 id="reference">Reference</h2>
<p>阅读过程中还看到一些什么BAGS，进行数据分组的方法，这个方法肯定不会在我们的框架中使用，但是我们可以分析一下这种分组训练为什么会对长尾的场景存在差异。</p>
<ol>
<li>⭐&ldquo;Bag of Tricks for LT Visual Recognition with Deep Convolutional Neural Network&rdquo; <a href="https://zhuanlan.zhihu.com/p/416315017" target="_blank" rel="noopener">ZHIHU</a>
</li>
<li>⭐&ldquo;BBN: Bilateral-Branch Network with Cumulative Learning for Long-Tailed Visual Recognition&rdquo; <a href="https://zhuanlan.zhihu.com/p/373053356" target="_blank" rel="noopener">ZHIHU</a>
 CVPR20</li>
<li>❓&ldquo;Long-Tail Learning via Logit Abjustment&rdquo; ICLR 20 <a href="https://zhuanlan.zhihu.com/p/267058892" target="_blank" rel="noopener">zhihu1</a>
 | <a href="https://zhuanlan.zhihu.com/p/403981340" target="_blank" rel="noopener">zhihu2</a>
</li>
<li>&ldquo;Improving Calibration for Long-Tailed Recognition&rdquo; CVPR21 <a href="https://zhuanlan.zhihu.com/p/419911014" target="_blank" rel="noopener">zhihu</a>
</li>
<li>⭐&ldquo;Distribution Alignment: A Unified Framework for Long-tail Visual Recognition&rdquo; CVPR21 <a href="https://zhuanlan.zhihu.com/p/422891404" target="_blank" rel="noopener">zhihu</a>
 | <a href="https://zhuanlan.zhihu.com/p/385053738" target="_blank" rel="noopener">zhihu2</a>
</li>
<li>&ldquo;Decoupling Representation and Classifier for Long-Tailed Recognition&rdquo; ICLR20</li>
<li>&ldquo;Long-Tailed Classification by Keeping the Good and Removing the Bad Momentum Causal Effect&rdquo; NIPS20 | <a href="https://zhuanlan.zhihu.com/p/259569655" target="_blank" rel="noopener">zhihu</a>
</li>
<li>&ldquo;Rethinking the Value of Labels for Improving Class-Imbalanced Learning&rdquo; NIPS20| <a href="https://zhuanlan.zhihu.com/p/390106051" target="_blank" rel="noopener">zhihu</a>
</li>
<li>&ldquo;Contrastive Learning based Hybrid Networks for Long-Tailed Image Classification&rdquo; CVPR21 <a href="https://zhuanlan.zhihu.com/p/405043879" target="_blank" rel="noopener">zhihu</a>
</li>
</ol>
<p>总结性串讲：</p>
<ol>
<li><a href="https://www.cnblogs.com/fusheng-rextimmy/p/15389065.html" target="_blank" rel="noopener">LT-Classification</a>
</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>Loss-NCE</title>
      <link>https://aikenh.cn/posts/loss-nce/</link>
      <pubDate>Wed, 22 Dec 2021 13:39:55 +0000</pubDate>
      <guid>https://aikenh.cn/posts/loss-nce/</guid>
      <description>&lt;p&gt;@AikenHong 2021&lt;/p&gt;
&lt;p&gt;Noise Contrastive Estimation Loss = NCE Loss 噪声对比估计损失，这里的Noise实际上就是Negative Samples.
该损失被广泛的用于对比学习的任务，而对比学习广泛的作为自监督学习的无监督子任务用来训练一个良好的特征提取器，于是对于对比学习的目标和效用的理解十分关键。&lt;/p&gt;
&lt;h2 id=&#34;whats-nce-loss&#34;&gt;What&amp;rsquo;s NCE Loss&lt;/h2&gt;
&lt;p&gt;在介绍NCE之前我们可以将其和CE进行一个简单的对比，虽然名称上不是同一个CE，但是在数学表达上却有很相近的地方（softmax-kind of loss）&lt;/p&gt;
&lt;p&gt;首先softmax，他保证所有的值加起来为一，结合onehot的ce，实际上&lt;code&gt;j==gt&lt;/code&gt;的情况下外层+log也就是ceLoss，也就是 $logSoftmax$&lt;/p&gt;
&lt;div&gt;
$$ 
S_j = \frac{e^{a_j}}{\sum_{k=1}^N e^{a_k}}
 $$
&lt;/div&gt;
&lt;p&gt;然后看infoNCE，基础的对比学习损失可以写成：&lt;/p&gt;
&lt;div&gt;
$$ 
L_{contrast} = \mathbb{E}[-\log\frac{e^{f_x^T f_y/T}}{e^{f_x^T f_y/T} + \sum_i e^{f_x^T f_{y_-^i}/T}}]
 $$
&lt;/div&gt;
&lt;p&gt;其中 $f_x^T f_y^T$ 为 $sim(x,y)$ 时即转化为带 $T$ 的NCE，即InforNCE.&lt;/p&gt;
&lt;p&gt;分子是正例对的相似度，分母是正例对+所有负例对的相似度，最小化infoNCE loss，就是去最大化分子的同时最小化分母，也就是最大化正例对的相似度，最小化负例对的相似度。&lt;/p&gt;
&lt;p&gt;从该形式上看，和soft的CE形式上是统一的，当我们把分母看作概率和自身以及和其他的相似性，这样和NCE在形式上和简化后的CE实现了统一。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;但是我不认为这和label smooth 后的CE有相关性，而是和原始的CE经由One-hot简化后结构上有相似性。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;how-it-works&#34;&gt;How it Works&lt;/h2&gt;
&lt;p&gt;NCE的思想是&lt;strong&gt;拉近相似的样本，推开不相近的样本&lt;/strong&gt;，从而学习到一个好的&lt;strong&gt;语义表示空间&lt;/strong&gt;，这一点上实际上和度量学习的思想是一样的，只是对比学习通常作用在无监督或者自监督的语境中，度量学习这是有监督的。&lt;/p&gt;
&lt;p&gt;考虑之前人脸匹配的研究，使用 &amp;ldquo;Alignment and Uniformity on the Hypersphere&amp;quot;中的Alignment and Uniformity，就是一个更好理解他的角度&lt;/p&gt;
&lt;div&gt;
$$ 
\begin{gathered}
L_{\text {contrast }}=\mathbb{E}\left[-\log \frac{e^{f_{x}^{T} f_{y} / \tau}}{e^{f_{x}^{T} f_{y} / \tau}+\sum_{i} e^{T_{x}^{T} f_{y_{i}}^{-} / \tau}}\right] \\
=\mathbb{E}\left[-f_{x}^{T} f_{y} / \tau\right]+\mathbb{E}\left[\log \left(e^{f_{x}^{T} f_{y} / \tau}+\sum_{i} e^{f_{x}^{T} f_{y_{i}^{-} / \tau}}\right)\right] \\
\mathbb{P}\left[\left(f_{x}=f_{y}\right)\right]=1 \underbrace{\mathbb{E}\left[-f_{x}^{T} f_{y} / \tau\right]}_{\text {positive alignment }}+\underbrace{\mathbb{E}\left[\log \left(e^{1 / \tau}+\sum_{i} e^{f_{x}^{T} f_{y_{i}}-/ \tau}\right)\right]}_{\text {uniformity }}
\end{gathered}
 $$
&lt;/div&gt;
&lt;p&gt;公式经过上面的推导就可以看成下的两个部分，其中&lt;strong&gt;alignment&lt;/strong&gt;只与&lt;strong&gt;positive pair&lt;/strong&gt;有关，相反&lt;strong&gt;Uniformity&lt;/strong&gt;只与&lt;strong&gt;negative pair&lt;/strong&gt;相关，希望所有的点都能尽可能的分布在uni hypersphere上。&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>@AikenHong 2021</p>
<p>Noise Contrastive Estimation Loss = NCE Loss 噪声对比估计损失，这里的Noise实际上就是Negative Samples.
该损失被广泛的用于对比学习的任务，而对比学习广泛的作为自监督学习的无监督子任务用来训练一个良好的特征提取器，于是对于对比学习的目标和效用的理解十分关键。</p>
<h2 id="whats-nce-loss">What&rsquo;s NCE Loss</h2>
<p>在介绍NCE之前我们可以将其和CE进行一个简单的对比，虽然名称上不是同一个CE，但是在数学表达上却有很相近的地方（softmax-kind of loss）</p>
<p>首先softmax，他保证所有的值加起来为一，结合onehot的ce，实际上<code>j==gt</code>的情况下外层+log也就是ceLoss，也就是 $logSoftmax$</p>
<div>
$$ 
S_j = \frac{e^{a_j}}{\sum_{k=1}^N e^{a_k}}
 $$
</div>
<p>然后看infoNCE，基础的对比学习损失可以写成：</p>
<div>
$$ 
L_{contrast} = \mathbb{E}[-\log\frac{e^{f_x^T f_y/T}}{e^{f_x^T f_y/T} + \sum_i e^{f_x^T f_{y_-^i}/T}}]
 $$
</div>
<p>其中 $f_x^T f_y^T$ 为 $sim(x,y)$ 时即转化为带 $T$ 的NCE，即InforNCE.</p>
<p>分子是正例对的相似度，分母是正例对+所有负例对的相似度，最小化infoNCE loss，就是去最大化分子的同时最小化分母，也就是最大化正例对的相似度，最小化负例对的相似度。</p>
<p>从该形式上看，和soft的CE形式上是统一的，当我们把分母看作概率和自身以及和其他的相似性，这样和NCE在形式上和简化后的CE实现了统一。</p>
<blockquote>
<p>但是我不认为这和label smooth 后的CE有相关性，而是和原始的CE经由One-hot简化后结构上有相似性。</p>
</blockquote>
<h2 id="how-it-works">How it Works</h2>
<p>NCE的思想是<strong>拉近相似的样本，推开不相近的样本</strong>，从而学习到一个好的<strong>语义表示空间</strong>，这一点上实际上和度量学习的思想是一样的，只是对比学习通常作用在无监督或者自监督的语境中，度量学习这是有监督的。</p>
<p>考虑之前人脸匹配的研究，使用 &ldquo;Alignment and Uniformity on the Hypersphere&quot;中的Alignment and Uniformity，就是一个更好理解他的角度</p>
<div>
$$ 
\begin{gathered}
L_{\text {contrast }}=\mathbb{E}\left[-\log \frac{e^{f_{x}^{T} f_{y} / \tau}}{e^{f_{x}^{T} f_{y} / \tau}+\sum_{i} e^{T_{x}^{T} f_{y_{i}}^{-} / \tau}}\right] \\
=\mathbb{E}\left[-f_{x}^{T} f_{y} / \tau\right]+\mathbb{E}\left[\log \left(e^{f_{x}^{T} f_{y} / \tau}+\sum_{i} e^{f_{x}^{T} f_{y_{i}^{-} / \tau}}\right)\right] \\
\mathbb{P}\left[\left(f_{x}=f_{y}\right)\right]=1 \underbrace{\mathbb{E}\left[-f_{x}^{T} f_{y} / \tau\right]}_{\text {positive alignment }}+\underbrace{\mathbb{E}\left[\log \left(e^{1 / \tau}+\sum_{i} e^{f_{x}^{T} f_{y_{i}}-/ \tau}\right)\right]}_{\text {uniformity }}
\end{gathered}
 $$
</div>
<p>公式经过上面的推导就可以看成下的两个部分，其中<strong>alignment</strong>只与<strong>positive pair</strong>有关，相反<strong>Uniformity</strong>只与<strong>negative pair</strong>相关，希望所有的点都能尽可能的分布在uni hypersphere上。</p>
<p>这样均匀的分布有利于聚类并且线性可分，且经过实验证实无监督对比学习确实能得到强判别力的特征。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211217113936.png">
    <img alt="NCE" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211217113936.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211217113936.png" style="display: block; margin: 0 auto;"
      alt="NCE"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>Alignment：指的是相似的例子，也就是正例，映射到单位超球面后，应该有接近的特征，也就是在超球面上距离比较近；</p>
<p>Uniformity：指的是系统应该倾向于在特征里保留尽可能多的信息，这等价于使得映射到单位超球面的特征，尽可能均匀的分布在球面上，分布的越均匀，意味着保留的信息越充分。分布均匀意味着两两有差异，也意味着各自保有独有信息，这代表信息保留充分。</p>
<blockquote>
<p>参考Label Smooth中Soft Label的定义，当我们将特征拉到超球面上均匀分布的时候，特征之间相对的距离关系，远近是否应该保留真实分布中的相似性和度量分布？NCE Loss是否能保留这种关系呢？</p>
</blockquote>
<p><em>这种额外的Info可能能够对于后续的蒸馏学习有一个比较大的影响</em></p>
<h2 id="with-self-supervised-learning">With Self-Supervised Learning</h2>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211219174256.png">
    <img alt="contrastive" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211219174256.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211219174256.png" style="display: block; margin: 0 auto;"
      alt="contrastive"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>

自监督学习最重要的就是下游任务的设计，一般分成两种：</p>
<ol>
<li>生成式模型：Encode-Decode架构，让输入输出尽可能的相似，或者是后续进化的MIM架构，挖空并还原空中的内容，并在Transformer架构中取代判别式模型方法称为主流。</li>
<li>判别式模型：通过Encoder编码，通过对比学习分析相似性来建立对比损失，自从MoCo出来后判别式模型在一定时间内成为主流。</li>
</ol>
<h3 id="避免退化解形成">避免退化解形成</h3>
<p>InfoNCE的两部分在理论上是缺一不可的，如果没有Alignment，就无法聚类，如果没有Uniformly，容易使得所有的输入输出又相同的表示，也就是形成退化解。</p>
<p>参考 <a href="https://mp.weixin.qq.com/s?__biz=Mzg4MjQ1NzI0NA==&amp;mid=2247494486&amp;idx=1&amp;sn=dd8700c12d394bcc4eb032ed09b508b7&amp;chksm=cf54c4a5f8234db3df5d82cc7839a6d8dc38991e495bfbda0f3b75a643c1686f1fe5c93502a3&amp;token=1062986518&amp;lang=zh_CN#rd" target="_blank" rel="noopener">Article</a>
 对几种自监督的方法解决退化解的方式进行了简要的分析。</p>
<h3 id="实验中的设置问题">实验中的设置问题</h3>
<p><a href="https://zhuanlan.zhihu.com/p/378340148" target="_blank" rel="noopener">zhihu</a>

<strong>对比学习中一般选择一个batch中的其他样本作为负例，如果负例中又很相似的样本怎么办？</strong></p>
<p>在无监督无标注的情况下，这样的伪负例，其实是不可避免的，首先可以想到的方式是去扩大语料库，去加大batch size，以降低batch训练中采样到伪负例的概率，减少它的影响。</p>
<p>另外，神经网络是有一定容错能力的，像伪标签方法就是一个很好的印证，但前提是错误标签数据或伪负例占较小的比例。</p>
<p>也可以考虑使用监督的对比学习方法</p>
<p><strong>对比学习的infoNCE loss 中的温度系数t的作用是什么？</strong><sub>[1]</sub></p>
<blockquote>
<p>温度系数的作用是调节对困难样本的关注程度：越小的温度系数越关注于将本样本和最相似的困难样本分开，去得到更均匀的表示。然而困难样本往往是与本样本相似程度较高的，很多困难负样本其实是潜在的正样本，过分强迫与困难样本分开会破坏学到的潜在语义结构，因此，温度系数不能过小
考虑两个极端情况，温度系数趋向于0时，对比损失退化为只关注最困难的负样本的损失函数；当温度系数趋向于无穷大时，对比损失对所有负样本都一视同仁，失去了困难样本关注的特性。</p>
</blockquote>
<p>也可以用另一个角度理解：</p>
<blockquote>
<p>可以把不同的负样本想像成同极点电荷在不同距离处的受力情况，距离越近的点电荷受到的库伦斥力更大，而距离越远的点电荷受到的斥力越小。
对比损失中，越近的负例受到的斥力越大，具体的表现就是对应的负梯度值越大[4]。这种性质更有利于形成在超球面均匀分布的特征。</p>
</blockquote>
<p>对照公式去理解：</p>
<div>
$$ 
L_{i}=-\log \left(e^{S\left(z_{i}, z_{i}^{+}\right) / \tau} / \sum_{j=0}^{K} e^{S\left(z_{i}, _{j}\right) / \tau}\right)
 $$
</div>
<p>当温度系数很小时，越相似也即越困难的负例，对应的坟墓就会越大，在分母叠加项中所占的比重就会越大，对整体loss的影响就会越大，具体的表现就是对应的负梯度值越大</p>
<p>当然，这仅仅是提供了一种定性的认识，定量的认识和推导可以参见博客<a href="https://zhuanlan.zhihu.com/p/357071960" target="_blank" rel="noopener">zhihu</a>
</p>
<h2 id="with-supervised-learning">with supervised learning</h2>
<p><a href="https://zhuanlan.zhihu.com/p/143443691" target="_blank" rel="noopener">ZHIHU</a>
</p>
<p>借鉴了contrastive的设计在监督信息的基础上对其进行改造，设计一个用于监督学习的对比损失。这一点也可以解决我们问题设置中的第一个问题，但是为此也只能在监督的情况下使用。</p>
<div>
$$ 
\mathcal{L}_{i}^{s u p}=\frac{-1}{2 N_{\tilde{y}_{i}}-1} \sum_{j=1}^{2 N} 1_{i \neq j} \cdot 1_{\bar{y}_{i}=\bar{y}_{j}} \cdot \log \frac{\exp \left(z_{i} \cdot z_{j} / \tau\right)}{\sum_{k=1}^{2 N} 1_{i \neq k} \cdot \exp \left(z_{i} \cdot z_{k} / \tau\right)}
 $$
</div>
<p>其实也就是当标签相同的时候都当作正例，其他时候都是负例，也就是修改了原本状态下positive的情况。</p>
<p>在训练的过程中，该方法和two-stage会使用同样的策略，也就是在第一阶段使用SCL训练Backbone，在第二阶段固定representation的参数，并只对clf的参数进行训练。</p>
<h4 id="code-part">Code Part</h4>
<p><a href="https://www.cnblogs.com/panchuangai/p/13764774.html" target="_blank" rel="noopener">understand the code</a>
；<a href="https://github.com/HobbitLong/SupContrast/blob/a8a275b3a8b9b9bdc9c527f199d5b9be58148543/main_supcon.py#L131" target="_blank" rel="noopener">Offical Code</a>
；</p>
<ul>
<li>如果我们需要理解这串代码如何使用，我们需要阅读官方源码中的数据使用模式，我们需要使用图像的两组不同增强，计算对应的特征，然后整合到n_views维度，再将其传入该损失。</li>
<li>后续我们可以基于NXTent Loss函数来简化和改写该损失，目前我们只需要对其加入Normalization就可以暂时进行使用了，第一步我们使用大的batchsize来代替2Augs，如果效果不好的话可以测试2Augs是否会有更好的增益</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">torch</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">torch.nn</span> <span class="k">as</span> <span class="nn">nn</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">SupConLoss</span><span class="p">(</span><span class="n">nn</span><span class="o">.</span><span class="n">Module</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Supervised Contrastive Learning: https://arxiv.org/pdf/2004.11362.pdf.
</span></span></span><span class="line"><span class="cl"><span class="s2">    It also supports the unsupervised contrastive loss in SimCLR&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">temperature</span><span class="o">=</span><span class="mf">0.07</span><span class="p">,</span> <span class="n">contrast_mode</span><span class="o">=</span><span class="s1">&#39;all&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                 <span class="n">base_temperature</span><span class="o">=</span><span class="mf">0.07</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="nb">super</span><span class="p">(</span><span class="n">SupConLoss</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">temperature</span> <span class="o">=</span> <span class="n">temperature</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">contrast_mode</span> <span class="o">=</span> <span class="n">contrast_mode</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">base_temperature</span> <span class="o">=</span> <span class="n">base_temperature</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">features</span><span class="p">,</span> <span class="n">labels</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">mask</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;&#34;&#34;Compute loss for model. If both `labels` and `mask` are None,
</span></span></span><span class="line"><span class="cl"><span class="s2">        it degenerates to SimCLR unsupervised loss:
</span></span></span><span class="line"><span class="cl"><span class="s2">        https://arxiv.org/pdf/2002.05709.pdf
</span></span></span><span class="line"><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="cl"><span class="s2">        Args:
</span></span></span><span class="line"><span class="cl"><span class="s2">            features: hidden vector of shape [bsz, n_views, ...].
</span></span></span><span class="line"><span class="cl"><span class="s2">            labels: ground truth of shape [bsz].
</span></span></span><span class="line"><span class="cl"><span class="s2">            mask: contrastive mask of shape [bsz, bsz], mask_{i,j}=1 if sample j
</span></span></span><span class="line"><span class="cl"><span class="s2">                has the same class as sample i. Can be asymmetric.
</span></span></span><span class="line"><span class="cl"><span class="s2">        Returns:
</span></span></span><span class="line"><span class="cl"><span class="s2">            A loss scalar.
</span></span></span><span class="line"><span class="cl"><span class="s2">        &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="n">device</span> <span class="o">=</span> <span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">device</span><span class="p">(</span><span class="s1">&#39;cuda&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                  <span class="k">if</span> <span class="n">features</span><span class="o">.</span><span class="n">is_cuda</span>
</span></span><span class="line"><span class="cl">                  <span class="k">else</span> <span class="n">torch</span><span class="o">.</span><span class="n">device</span><span class="p">(</span><span class="s1">&#39;cpu&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">features</span><span class="o">.</span><span class="n">shape</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">&#39;`features` needs to be [bsz, n_views, ...],&#39;</span>
</span></span><span class="line"><span class="cl">                             <span class="s1">&#39;at least 3 dimensions are required&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">features</span><span class="o">.</span><span class="n">shape</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">3</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">features</span> <span class="o">=</span> <span class="n">features</span><span class="o">.</span><span class="n">view</span><span class="p">(</span><span class="n">features</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">features</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">batch_size</span> <span class="o">=</span> <span class="n">features</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">labels</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">mask</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">&#39;Cannot define both `labels` and `mask`&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">elif</span> <span class="n">labels</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">mask</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">mask</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">eye</span><span class="p">(</span><span class="n">batch_size</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">float32</span><span class="p">)</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">elif</span> <span class="n">labels</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">labels</span> <span class="o">=</span> <span class="n">labels</span><span class="o">.</span><span class="n">contiguous</span><span class="p">()</span><span class="o">.</span><span class="n">view</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">labels</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="n">batch_size</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">&#39;Num of labels does not match num of features&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">mask</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">eq</span><span class="p">(</span><span class="n">labels</span><span class="p">,</span> <span class="n">labels</span><span class="o">.</span><span class="n">T</span><span class="p">)</span><span class="o">.</span><span class="n">float</span><span class="p">()</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">mask</span> <span class="o">=</span> <span class="n">mask</span><span class="o">.</span><span class="n">float</span><span class="p">()</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">contrast_count</span> <span class="o">=</span> <span class="n">features</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="n">contrast_feature</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">cat</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">unbind</span><span class="p">(</span><span class="n">features</span><span class="p">,</span> <span class="n">dim</span><span class="o">=</span><span class="mi">1</span><span class="p">),</span> <span class="n">dim</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">contrast_mode</span> <span class="o">==</span> <span class="s1">&#39;one&#39;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">anchor_feature</span> <span class="o">=</span> <span class="n">features</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">            <span class="n">anchor_count</span> <span class="o">=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">        <span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">contrast_mode</span> <span class="o">==</span> <span class="s1">&#39;all&#39;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">anchor_feature</span> <span class="o">=</span> <span class="n">contrast_feature</span>
</span></span><span class="line"><span class="cl">            <span class="n">anchor_count</span> <span class="o">=</span> <span class="n">contrast_count</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">&#39;Unknown mode: </span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">contrast_mode</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># compute logits</span>
</span></span><span class="line"><span class="cl">        <span class="n">anchor_dot_contrast</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">div</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">torch</span><span class="o">.</span><span class="n">matmul</span><span class="p">(</span><span class="n">anchor_feature</span><span class="p">,</span> <span class="n">contrast_feature</span><span class="o">.</span><span class="n">T</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="bp">self</span><span class="o">.</span><span class="n">temperature</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># for numerical stability</span>
</span></span><span class="line"><span class="cl">        <span class="n">logits_max</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="n">anchor_dot_contrast</span><span class="p">,</span> <span class="n">dim</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">keepdim</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">logits</span> <span class="o">=</span> <span class="n">anchor_dot_contrast</span> <span class="o">-</span> <span class="n">logits_max</span><span class="o">.</span><span class="n">detach</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># tile mask</span>
</span></span><span class="line"><span class="cl">        <span class="n">mask</span> <span class="o">=</span> <span class="n">mask</span><span class="o">.</span><span class="n">repeat</span><span class="p">(</span><span class="n">anchor_count</span><span class="p">,</span> <span class="n">contrast_count</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># mask-out self-contrast cases</span>
</span></span><span class="line"><span class="cl">        <span class="n">logits_mask</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">scatter</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">torch</span><span class="o">.</span><span class="n">ones_like</span><span class="p">(</span><span class="n">mask</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">torch</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="n">batch_size</span> <span class="o">*</span> <span class="n">anchor_count</span><span class="p">)</span><span class="o">.</span><span class="n">view</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="mi">0</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">mask</span> <span class="o">=</span> <span class="n">mask</span> <span class="o">*</span> <span class="n">logits_mask</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># compute log_prob</span>
</span></span><span class="line"><span class="cl">        <span class="n">exp_logits</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">exp</span><span class="p">(</span><span class="n">logits</span><span class="p">)</span> <span class="o">*</span> <span class="n">logits_mask</span>
</span></span><span class="line"><span class="cl">        <span class="n">log_prob</span> <span class="o">=</span> <span class="n">logits</span> <span class="o">-</span> <span class="n">torch</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="n">exp_logits</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">keepdim</span><span class="o">=</span><span class="kc">True</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># compute mean of log-likelihood over positive</span>
</span></span><span class="line"><span class="cl">        <span class="n">mean_log_prob_pos</span> <span class="o">=</span> <span class="p">(</span><span class="n">mask</span> <span class="o">*</span> <span class="n">log_prob</span><span class="p">)</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">/</span> <span class="n">mask</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># loss</span>
</span></span><span class="line"><span class="cl">        <span class="n">loss</span> <span class="o">=</span> <span class="o">-</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">temperature</span> <span class="o">/</span> <span class="bp">self</span><span class="o">.</span><span class="n">base_temperature</span><span class="p">)</span> <span class="o">*</span> <span class="n">mean_log_prob_pos</span>
</span></span><span class="line"><span class="cl">        <span class="n">loss</span> <span class="o">=</span> <span class="n">loss</span><span class="o">.</span><span class="n">view</span><span class="p">(</span><span class="n">anchor_count</span><span class="p">,</span> <span class="n">batch_size</span><span class="p">)</span><span class="o">.</span><span class="n">mean</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">loss</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="with-arcface">with ArcFace</h2>
<p>对比学习损失我们知道其目的是为了，拉近相似样本之间的距离，并尽量的将不同的类别之间的样本区分，而这和进行人脸识别中的 $ArcFace Loss$ 系列的Softmax Loss有着相同的目的。</p>
<p>那么这两种方法之间是否能够相互借鉴，或者说是否NCE本身在自监督学习任务上就更优于ArcFace?（是否会过度关注细节，无法关注到相应的整体架构）

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211220154555.png">
    <img alt="arcface" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211220154555.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211220154555.png" style="display: block; margin: 0 auto;"
      alt="arcface"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>或者说在后续的分类器训练过程中，这样是否能够帮助我们使用聚类的方式进行分类？（结合epoch-control的那种方法）进行fine-tuning等等</p>
<h2 id="reference">reference</h2>
<ol>
<li>“Understanding the Behaviour of Contrastive Loss” CVPR2021</li>
<li><a href="https://zhuanlan.zhihu.com/p/357071960" target="_blank" rel="noopener">Analysis The InfoNCE-Loss</a>
</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>Loss-Smooth(Sharpen)</title>
      <link>https://aikenh.cn/posts/loss-smoothsharpen/</link>
      <pubDate>Fri, 17 Dec 2021 03:35:27 +0000</pubDate>
      <guid>https://aikenh.cn/posts/loss-smoothsharpen/</guid>
      <description>&lt;p&gt;@AikenHong 2021
@topic&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;smooth label (inception v2)&lt;/li&gt;
&lt;li&gt;when does label smoothing help (nips 2019)&lt;/li&gt;
&lt;li&gt;sharpen in semi-supervised in the future&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/seominseok0429/label-smoothing-visualization-pytorch?utm_source=catalyzex.com&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;offical code github&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不是一个通用的方法，在很多的任务上反而会导致掉点的现象，可以简单分析一下，汲取一下思想和Sharpen做对比，在这篇文章中，我们可以结合之前的人脸对比损失来进行分析。&lt;/p&gt;
&lt;h2 id=&#34;whats-the-smooth-label&#34;&gt;What&amp;rsquo;s the smooth label&lt;/h2&gt;
&lt;p&gt;首先介绍在图像分类任务中对logits和Hard label做ce得到我们的损失，可以表现为如下的形式：&lt;/p&gt;
&lt;div&gt;
$$ 
Loss = -\sum^{K}_{i=1}p_i \log(q_i)
 $$
&lt;/div&gt;
&lt;p&gt;由于我们的标签是一个hard label，实际上可以转化成一个one-hot，即&lt;/p&gt;
&lt;div&gt;
$$ 
\begin{equation}
p_i = \left\{
\begin{array}{c1}
1 &amp; i==gt \\
0 &amp; i!=gt \\
\end{array} \right.
\end{equation}
 $$
&lt;/div&gt;
&lt;p&gt;而soft label实际上做的是将 1的位置变为 $1-\alpha$ ，其他位置设置为 $\alpha/(K-1)$ ，然后再去求CE，&lt;/p&gt;
&lt;p&gt;Hinton论文中给出该损失对特征分布的作用测试图：

&lt;div class=&#34;post-img-view&#34;&gt;
  &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211216194040.png&#34;&gt;
    &lt;img loading=&#34;lazy&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211216194040.png&#34;class=&#34;responsive-image&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211216194040.png&#34; style=&#34;display: block; margin: 0 auto;&#34;
      alt=&#34;&#34;  /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;script&gt;
  document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
      var images = document.querySelectorAll(&#34;.responsive-image&#34;);
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + &#34;px&#34;;
      });
  });
&lt;/script&gt;
&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>@AikenHong 2021
@topic</p>
<ul>
<li>smooth label (inception v2)</li>
<li>when does label smoothing help (nips 2019)</li>
<li>sharpen in semi-supervised in the future</li>
<li><a href="https://github.com/seominseok0429/label-smoothing-visualization-pytorch?utm_source=catalyzex.com" target="_blank" rel="noopener">offical code github</a>
</li>
</ul>
<p>不是一个通用的方法，在很多的任务上反而会导致掉点的现象，可以简单分析一下，汲取一下思想和Sharpen做对比，在这篇文章中，我们可以结合之前的人脸对比损失来进行分析。</p>
<h2 id="whats-the-smooth-label">What&rsquo;s the smooth label</h2>
<p>首先介绍在图像分类任务中对logits和Hard label做ce得到我们的损失，可以表现为如下的形式：</p>
<div>
$$ 
Loss = -\sum^{K}_{i=1}p_i \log(q_i)
 $$
</div>
<p>由于我们的标签是一个hard label，实际上可以转化成一个one-hot，即</p>
<div>
$$ 
\begin{equation}
p_i = \left\{
\begin{array}{c1}
1 & i==gt \\
0 & i!=gt \\
\end{array} \right.
\end{equation}
 $$
</div>
<p>而soft label实际上做的是将 1的位置变为 $1-\alpha$ ，其他位置设置为 $\alpha/(K-1)$ ，然后再去求CE，</p>
<p>Hinton论文中给出该损失对特征分布的作用测试图：

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211216194040.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211216194040.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211216194040.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="pros-and-cons">Pros and Cons</h3>
<p><a href="https://arxiv.org/pdf/1906.02629.pdf" target="_blank" rel="noopener">why does label smoothing help</a>
</p>
<blockquote>
<p>校准性：模型预测的分数能不能同时表征其置信度</p>
</blockquote>
<ol>
<li>LS可以提高模型的泛化性，同时还能提高模型的校准性（model calibration）</li>
<li>在模型蒸馏中，如果我们的teacher model是由LS训练的，Teacher的效果更好，但是Student的性能会变差，这是因为LS的作用是将相同类别的example聚类到更加紧促的cluster中，但是这也导致了，不同样本之间的相似性信息的损失，从而影响了蒸馏的效果</li>
</ol>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211216202042.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211216202042.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211216202042.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>此外模型的校准性能，通常可以使用T系数来进行优化，Temprature scaling（TS）可以有效的降低ECE（expected calibration error）</p>
<blockquote>
<p>（TS就是在计算cross entropy之前把模型的输出除以超参T，然后再参与cross entropy的计算，比较典型的应用就是在蒸馏中对teacher模型 soft label 处理）</p>
</blockquote>
<h2 id="how-it-work">How it work</h2>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211216200856.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211216200856.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211216200856.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>从特征输出的信息来看，启用了LS（loss smooth）的特征的Feature Norm比没有启用小得多，特征空间减小的话，实际上就是降低softmax中的s值（长度，还有另一个指标是角度）</p>
<p>==较低的s值==会有这样的几个作用：</p>
<ul>
<li>softmax prob的最大值降低，这样我们就可以永远在线性优化区，几乎不存在平滑区域，这样样本向中心的聚拢程度会更高</li>
<li>s过小的话，对于人脸匹配（往往设置较大的s），为了有更宽广的判别面，使得精度更高，对应于Hard Sample（Task）也是一样的到理道理，就会起到反作用。</li>
</ul>
<blockquote>
<p>Label Smoothing起到的作用实际上是抑制了feature norm，此时softmax prob永远无法达到设定的 $1-\alpha/k-1$  ，loss曲面上不再存在平缓区域，处处都有较大的梯度指向各个类中心，所以特征会更加聚拢。而之所以人脸上不work，是因为我们通常会使用固定的s，此时Label Smoothing无法控制feature norm，只能控制角度，就会起到反向优化的作用</p>
</blockquote>
<h3 id="feature-norm">Feature Norm</h3>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211216210444.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211216210444.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211216210444.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>BTW：对比损失可以分为alignment和uniformity部分</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211216204355.png">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211216204355.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211216204355.png" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>第一部分和正样例有关，第二部分仅和负样例有关，作用是远近。</p>
<h2 id="with-the-sharpen-label">With the Sharpen Label</h2>
<p>Sharpen实际上是和Smooth相反的过程, Sharpen使用的场景可能相对较少, 比如我们希望能最小化熵损失(Like Semi-Supervised), 让输出模型的置信度更高, 或者让分界面更加分明的情况.</p>
<div>
$$ 
Sharpen(p, T)_i= \frac {p_i^{1/T}} {\sum_{j=1}^L p_i^{1/T}}
 $$
</div>
<p>当T-&gt;0的时候,标签将趋向于ont-hot(Dirac)</p>
<p>而当我们去做FIL任务的时候, 我们拥有的标签实际上应该是One-Hot的, 所以我们需要分析是否需要对其去做smooth, 还是说我们结合SCL的特性, 用One-Hot这种Sharpen的标签去学一个更好的分界面.</p>
<h2 id="reference">reference</h2>
<p>⁉️<a href="https://zhuanlan.zhihu.com/p/410491474" target="_blank" rel="noopener">理解的是错的，从NCE角度</a>

参考个人对NCE的理解[[Papers/Loss-NCE]]</p>
<ol>
<li><a href="https://zhuanlan.zhihu.com/p/302843504" target="_blank" rel="noopener">可以结合里面的人脸对比损失的softmax</a>
</li>
<li><a href="https://blog.csdn.net/qiu931110/article/details/86684241" target="_blank" rel="noopener">basic</a>
 | <a href="https://zhuanlan.zhihu.com/p/359792244" target="_blank" rel="noopener">translate</a>
 | <a href="https://zhuanlan.zhihu.com/p/110120048" target="_blank" rel="noopener">better translate</a>
</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>Training Strategy</title>
      <link>https://aikenh.cn/posts/nerualnetworktraining/</link>
      <pubDate>Thu, 16 Dec 2021 08:34:44 +0000</pubDate>
      <guid>https://aikenh.cn/posts/nerualnetworktraining/</guid>
      <description>&lt;p&gt;@Aiken 2020，&lt;/p&gt;
&lt;p&gt;主要针对神经网络的训练过程中的一些基础策略的调整，比如当训练的曲线出现一定的问题的时候，我们应该怎么去调整我们训练过程中的策略。&lt;/p&gt;
&lt;p&gt;参数调整过程中最重要的就是优化器（优化或者说是下降算法）和学习率（优化算法的核心参数），此外像是数据增强策略还是Normalization策略，都能极大的影响一个模型的好坏。&lt;/p&gt;
&lt;h2 id=&#34;优化器&#34;&gt;优化器&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://wizardforcel.gitbooks.io/learn-dl-with-pytorch-liaoxingyu/content/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Some Material&lt;/a&gt;

实际上虽然有很多的优化算法，但是到最后最常用的还是 SGD+Mon 和 Adam两种：&lt;/p&gt;
&lt;p&gt;Adam主要的有事在于自适应学习率，他对我们设计的学习率实际上没有那么敏感，但是在具体实验中往往不会有调的好的SGD那么好，只是在SGD的参数调整中会比较费劲。&lt;/p&gt;
&lt;p&gt;但是有了根据patient调整lr的scheduler后，我们基本上可以使用SGD做一个较为简单的调整，只要设计好初始的lr的实验以及用来调整学习率的参数值。&lt;/p&gt;
&lt;h2 id=&#34;学习率&#34;&gt;学习率&lt;/h2&gt;
&lt;p&gt;$\omega^{n} \leftarrow \omega^{n}-\eta \frac{\partial L}{\partial \omega^{n}}$ 其中的权重就是学习率lr，&lt;/p&gt;
&lt;p&gt;==Basic==&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;/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;1. Loss爆炸 2.振荡&lt;/td&gt;
          &lt;td&gt;1.过拟合 2.收敛速度慢&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;学习率的基本设置&#34;&gt;学习率的基本设置&lt;/h3&gt;
&lt;p&gt;在训练过程中，一般根据训练轮数设置动态变化的学习率。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;刚开始训练时：学习率以 0.01 ~ 0.001 为宜。&lt;/li&gt;
&lt;li&gt;一定轮数过后：逐渐减缓。&lt;/li&gt;
&lt;li&gt;接近训练结束：学习速率的衰减应该在100倍以上。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Note：&lt;/strong&gt;
如果是 &lt;strong&gt;迁移学习&lt;/strong&gt; ，由于模型已在原始数据上收敛，此时应设置较小学习率 (≤10−4) 在新数据上进行 &lt;strong&gt;微调&lt;/strong&gt; 。&lt;/p&gt;
&lt;h3 id=&#34;学习率变化方法&#34;&gt;学习率变化方法&lt;/h3&gt;
&lt;p&gt;==warm up==&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.zhihu.com/question/338066667/answer/771252708&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;warm up为什么有用&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;warm up衰减策略与上述的策略有些不同，它是先从一个极低的学习率开始增加，增加到某一个值后再逐渐减少, 这点上倒是和Cosine Anneal LR有一定的相似之处，将这两种结合起来是一种常见的训练策略：&lt;/p&gt;
&lt;p&gt;这样训练模型更加稳定，因为在刚开始时模型的参数都是随机初始化的，此时如果学习率应该取小一点，这样就不会使模型一下子跑偏。&lt;/p&gt;
&lt;p&gt;而这样的跑偏对于&lt;strong&gt;大模型&lt;/strong&gt;而言，可能是导致很严重的影响，后面收敛了也可能不会达到最佳的效果，一开始的跑偏，可能会造成准确率在后面的严重结果。

&lt;div class=&#34;post-img-view&#34;&gt;
  &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211216001833.png&#34;&gt;
    &lt;img alt=&#34;warmup&#34; loading=&#34;lazy&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211216001833.png&#34;class=&#34;responsive-image&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211216001833.png&#34; style=&#34;display: block; margin: 0 auto;&#34;
      alt=&#34;warmup&#34;  /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;script&gt;
  document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
      var images = document.querySelectorAll(&#34;.responsive-image&#34;);
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + &#34;px&#34;;
      });
  });
&lt;/script&gt;
&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>@Aiken 2020，</p>
<p>主要针对神经网络的训练过程中的一些基础策略的调整，比如当训练的曲线出现一定的问题的时候，我们应该怎么去调整我们训练过程中的策略。</p>
<p>参数调整过程中最重要的就是优化器（优化或者说是下降算法）和学习率（优化算法的核心参数），此外像是数据增强策略还是Normalization策略，都能极大的影响一个模型的好坏。</p>
<h2 id="优化器">优化器</h2>
<p><a href="https://wizardforcel.gitbooks.io/learn-dl-with-pytorch-liaoxingyu/content/" target="_blank" rel="noopener">Some Material</a>

实际上虽然有很多的优化算法，但是到最后最常用的还是 SGD+Mon 和 Adam两种：</p>
<p>Adam主要的有事在于自适应学习率，他对我们设计的学习率实际上没有那么敏感，但是在具体实验中往往不会有调的好的SGD那么好，只是在SGD的参数调整中会比较费劲。</p>
<p>但是有了根据patient调整lr的scheduler后，我们基本上可以使用SGD做一个较为简单的调整，只要设计好初始的lr的实验以及用来调整学习率的参数值。</p>
<h2 id="学习率">学习率</h2>
<p>$\omega^{n} \leftarrow \omega^{n}-\eta \frac{\partial L}{\partial \omega^{n}}$ 其中的权重就是学习率lr，</p>
<p>==Basic==</p>
<table>
  <thead>
      <tr>
          <th></th>
          <th>学习率大</th>
          <th>学习率小</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>学习速度</td>
          <td>快</td>
          <td>慢</td>
      </tr>
      <tr>
          <td>使用情景</td>
          <td>刚开始训练时</td>
          <td>一定的次数过后</td>
      </tr>
      <tr>
          <td>副作用</td>
          <td>1. Loss爆炸 2.振荡</td>
          <td>1.过拟合 2.收敛速度慢</td>
      </tr>
  </tbody>
</table>
<h3 id="学习率的基本设置">学习率的基本设置</h3>
<p>在训练过程中，一般根据训练轮数设置动态变化的学习率。</p>
<ul>
<li>刚开始训练时：学习率以 0.01 ~ 0.001 为宜。</li>
<li>一定轮数过后：逐渐减缓。</li>
<li>接近训练结束：学习速率的衰减应该在100倍以上。</li>
</ul>
<p><strong>Note：</strong>
如果是 <strong>迁移学习</strong> ，由于模型已在原始数据上收敛，此时应设置较小学习率 (≤10−4) 在新数据上进行 <strong>微调</strong> 。</p>
<h3 id="学习率变化方法">学习率变化方法</h3>
<p>==warm up==</p>
<p><a href="https://www.zhihu.com/question/338066667/answer/771252708" target="_blank" rel="noopener">warm up为什么有用</a>
</p>
<p>warm up衰减策略与上述的策略有些不同，它是先从一个极低的学习率开始增加，增加到某一个值后再逐渐减少, 这点上倒是和Cosine Anneal LR有一定的相似之处，将这两种结合起来是一种常见的训练策略：</p>
<p>这样训练模型更加稳定，因为在刚开始时模型的参数都是随机初始化的，此时如果学习率应该取小一点，这样就不会使模型一下子跑偏。</p>
<p>而这样的跑偏对于<strong>大模型</strong>而言，可能是导致很严重的影响，后面收敛了也可能不会达到最佳的效果，一开始的跑偏，可能会造成准确率在后面的严重结果。

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211216001833.png">
    <img alt="warmup" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211216001833.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211216001833.png" style="display: block; margin: 0 auto;"
      alt="warmup"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl">    <span class="c1"># MultiStepLR without warm up</span>
</span></span><span class="line"><span class="cl">    <span class="n">scheduler</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">optim</span><span class="o">.</span><span class="n">lr_scheduler</span><span class="o">.</span><span class="n">MultiStepLR</span><span class="p">(</span><span class="n">optimizer</span><span class="p">,</span> \
</span></span><span class="line"><span class="cl">								<span class="n">milestones</span><span class="o">=</span><span class="n">args</span><span class="o">.</span><span class="n">milestones</span><span class="p">,</span> <span class="n">gamma</span><span class="o">=</span><span class="mf">0.1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># warm_up_with_multistep_lr</span>
</span></span><span class="line"><span class="cl">    <span class="n">warm_up_with_multistep_lr</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">epoch</span><span class="p">:</span> <span class="n">epoch</span> <span class="o">/</span> <span class="n">args</span><span class="o">.</span><span class="n">warm_up_epochs</span> <span class="k">if</span> \
</span></span><span class="line"><span class="cl">	<span class="n">epoch</span> <span class="o">&lt;=</span> <span class="n">args</span><span class="o">.</span><span class="n">warm_up_epochs</span> <span class="k">else</span> <span class="mf">0.1</span><span class="o">**</span><span class="nb">len</span><span class="p">([</span><span class="n">m</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">args</span><span class="o">.</span><span class="n">milestones</span> <span class="k">if</span> <span class="n">m</span> <span class="o">&lt;=</span> <span class="n">epoch</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="n">scheduler</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">optim</span><span class="o">.</span><span class="n">lr_scheduler</span><span class="o">.</span><span class="n">LambdaLR</span><span class="p">(</span><span class="n">optimizer</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">												  <span class="n">lr_lambda</span><span class="o">=</span><span class="n">warm_up_with_multistep_lr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># warm_up_with_cosine_lr</span>
</span></span><span class="line"><span class="cl">    <span class="n">warm_up_with_cosine_lr</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">epoch</span><span class="p">:</span> <span class="n">epoch</span> <span class="o">/</span> <span class="n">args</span><span class="o">.</span><span class="n">warm_up_epochs</span> <span class="k">if</span> \
</span></span><span class="line"><span class="cl">	<span class="n">epoch</span> <span class="o">&lt;=</span> <span class="n">args</span><span class="o">.</span><span class="n">warm_up_epochs</span> <span class="k">else</span> <span class="mf">0.5</span> <span class="o">*</span>\
</span></span><span class="line"><span class="cl">	<span class="p">(</span> <span class="n">math</span><span class="o">.</span><span class="n">cos</span><span class="p">((</span><span class="n">epoch</span> <span class="o">-</span> <span class="n">args</span><span class="o">.</span><span class="n">warm_up_epochs</span><span class="p">)</span> <span class="o">/</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">epochs</span> <span class="o">-</span> <span class="n">args</span><span class="o">.</span><span class="n">warm_up_epochs</span><span class="p">)</span> <span class="o">*</span> <span class="n">math</span><span class="o">.</span><span class="n">pi</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">scheduler</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">optim</span><span class="o">.</span><span class="n">lr_scheduler</span><span class="o">.</span><span class="n">LambdaLR</span><span class="p">(</span> <span class="n">optimizer</span><span class="p">,</span> <span class="n">lr_lambda</span><span class="o">=</span><span class="n">warm_up_with_cosine_lr</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>==Scheduler Setting：==</p>
<p>分组的学习率也能通过scheduler进行学习率的更新，可以放心使用。</p>
<table>
  <thead>
      <tr>
          <th>轮数减缓</th>
          <th>指数减缓</th>
          <th>分数减缓</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>step decay</td>
          <td>exponential decay</td>
          <td>1/t1/t decay</td>
      </tr>
      <tr>
          <td>每N轮学习率减半</td>
          <td>学习率按训练轮数增长指数插值递减</td>
          <td>lrt=lr0/(1+kt)，k 控制减缓幅度，t 为训练轮数</td>
      </tr>
  </tbody>
</table>
<p><a href="https://blog.csdn.net/weixin_42662358/article/details/93732852" target="_blank" rel="noopener">Pytorch的Scheduler</a>

pytorch中提供了很多scheduler的方法，其中用的最多的可能还是<code>multistep</code>，考虑到后续可能会用到基于指标调整的学习率，这里特别提一个<code>cosine</code>的学习率调整策略，它的学习率呈现的是一种周期变化的样子。</p>
<p>==Custom Scheduler==</p>
<p>Pytorch为可能的自定义提供了一个方便的Scheduler接口，<code>ReduceLROnPlateau</code>，通过<code>step</code> 调用指标的变化，进行学习率的调整，极其方便。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">scheduler</span> <span class="o">=</span> <span class="n">optim</span><span class="o">.</span><span class="n">lr_scheduler</span><span class="o">.</span><span class="n">ReduceLROnPlateau</span><span class="p">(</span><span class="n">optimizer</span><span class="p">,</span> <span class="n">mode</span><span class="o">=</span><span class="s1">&#39;max&#39;</span><span class="p">,</span>  
</span></span><span class="line"><span class="cl">			<span class="n">factor</span><span class="o">=</span><span class="mf">0.1</span><span class="p">,</span> <span class="n">patience</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">verbose</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">threshold</span><span class="o">=</span><span class="mf">1e-4</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">			<span class="n">threshold_model</span><span class="o">=</span><span class="s1">&#39;rel&#39;</span><span class="p">,</span> <span class="n">cooldown</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">min_lr</span><span class="o">=</span><span class="mf">1e-8</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">scheduler</span><span class="o">.</span><span class="n">step</span><span class="p">(</span><span class="n">acc</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>基本的参数包括：</p>
<ul>
<li>mode 很好理解，max（acc），min（loss）值</li>
<li>factor 学习率下降的参数</li>
<li>patience 多少次没有变化就调整</li>
<li>cooldown 调整后多久的冷却期</li>
<li>threshold，threshold_model 调整我们的动态上下限</li>
</ul>
<p><strong>threshold (float)</strong> – Threshold for measuring the new optimum, to only focus on significant changes. Default: 1e-4.</p>
<p><strong>threshold_mode (str)</strong> – One of rel, abs. In rel mode, <code>dynamic_threshold = best * ( 1 + threshold )</code> in ‘max’ mode or <code>best * ( 1 - threshold )</code> in min mode. In abs mode, dynamic_threshold = best + threshold in max mode or best - threshold in min mode. Default: ‘rel’.</p>
<h3 id="分析学习率的大小">分析学习率的大小</h3>
<p>在训练过程中可视化Loss下降曲线是相当重要的，那么针对Loss出现异常的情况我们应该怎么样去调整使得Loss逐步趋于正常呢？</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911210315.png">
    <img alt="image-20201120105459815" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911210315.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911210315.png" style="display: block; margin: 0 auto;"
      alt="image-20201120105459815"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>曲线 初始时 上扬 [红线]：（直接起飞梯度爆炸）
初始 <strong>学习率过大</strong> 导致 振荡，应减小学习率，并从头开始训练 。</p>
<p>曲线 初始时 强势下降 没多久 归于水平 [紫线]：
Solution：后期<strong>学习率过大</strong>导致无法拟合，应减小学习率，并重新训练后几轮 。</p>
<p>曲线 全程缓慢 [黄线]：
Solution：初始 <strong>学习率过小</strong> 导致收敛慢，应增大学习率，并从头开始训练 。</p>
<h2 id="过拟合欠拟合现象">过拟合欠拟合现象</h2>
<p>过拟合-&gt;各种泛化能力差的现象在这里我个人对这个现象的定义为以下的几种：</p>
<ul>
<li>训练阶段的准确率和验证/测试阶段的准确率相差大</li>
<li>训练过程和验证过程中的损失下降不一致，验证集中的准确率没有随着训练提升</li>
<li>典型的过拟合导致这样的现象</li>
</ul>
<p>下面整理一下<a href="https://www.bilibili.com/video/BV1ah411t7Pp?spm_id_from=333.999.0.0" target="_blank" rel="noopener">李沐对该部分的讲解</a>
</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211114181130.png">
    <img alt="image-20211114181128291" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211114181130.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211114181130.png" style="display: block; margin: 0 auto;"
      alt="image-20211114181128291"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>bug部分可能是由于增强做的过高或者问题太难, 但是在正常的表现下也不应该出现这种问题, 误差应该是差不多的.</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211114181412.png">
    <img alt="image-20211114181411611" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211114181412.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211114181412.png" style="display: block; margin: 0 auto;"
      alt="image-20211114181411611"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>上面的这张图片也说明了, 我们模型和问题的难度是需要相互匹配的, 如果不匹配就会出现各种各样的问题, 模型的复杂度, 通常可以从可学习参数的数来进行简单的判断的.</p>
<h3 id="过拟合问题定义和分析">过拟合问题定义和分析</h3>
<p>定义：模型对于训练集的假设过度严格，导致对训练集的数据拟合的“很好”，但是在测试验证集中效果不理想。可能会出现的典型现象如下：</p>
<ol>
<li>验证损失先下降后上升</li>
<li>训练集和测试集稳定后的准确率相差很大</li>
</ol>
<p>下面这张图, 显示的是模型的复杂度和相应的泛化和训练误差之间的关系, 在训练的时候复杂度还是需要自我调整.</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211026161951.png">
    <img alt="image-20211026161949994" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211026161951.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211026161951.png" style="display: block; margin: 0 auto;"
      alt="image-20211026161949994"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211114182734.png">
    <img alt="image-20211114182733584" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211114182734.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211114182734.png" style="display: block; margin: 0 auto;"
      alt="image-20211114182733584"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="收敛过快泛化能力差">收敛过快泛化能力差</h3>
<p>过拟合的一种衍生问题，当模型在训练集中快速收敛，在这种情况下可能会陷入极小值，由于损失太小，模型参数难以跳出极小值点，这种情况下，如果不加以约束会影响泛化能力，可以考虑使用，</p>
<ul>
<li><code>flood</code> 方法来设计我们的loss（效果未知，作为一种策略把，保证模型能够有一定量的损失，同时希望验证集上的损失能够下降到一个平缓的地方，来保证泛化能力）</li>
</ul>
<h3 id="产生的原因分析">产生的原因分析</h3>
<ol>
<li>训练数据样本单一，数据量不足</li>
<li>噪声干扰过大：失去了真实的输入输出之间的关系</li>
<li>模型的复杂度太高，足够死记硬背所有训练集的数据，导致不知道变通</li>
</ol>
<h3 id="数据的复杂度分析">数据的复杂度分析:</h3>
<p>大部分情况下进行数据的对比还是一个比较直观的情况, 其实可以从这几个方面进行比较</p>
<ul>
<li>数据集的样本数, 类别</li>
<li>数据集的分辨率</li>
<li>数据的时空结构和多样性</li>
</ul>
<h3 id="常见的解决方式">常见的解决方式</h3>
<ol>
<li>
<p>:zap:添加正则化L1，L2（weight decay），</p>
<p>weight decay等权重下降的方法，需要熟练掌握在pytorch上的设置</p>
</li>
<li>
<p>:zap:降低模型的复杂度，对应模型的设计和问题的规模需要更好的分析。</p>
</li>
<li>
<p>:zap:数据增强，使得数据的多样化指标进一步上升</p>
</li>
<li>
<p>:zap:Dropout，Early Stop</p>
</li>
<li>
<p>BatchNormalization</p>
</li>
<li>
<p>集成学习方法，通过对多个模型进行集成来降低单一模型的过拟合风险</p>
</li>
</ol>
<h3 id="图像增强">图像增强</h3>
<p>这里我们为图像增强另外开一个文档，图像增强的内容实际上可以考虑《数字图像处理》的这样一门课。</p>
<p><a href="https://mp.weixin.qq.com/s/tV5eSx73fzMovq0d7Jvu9Q" target="_blank" rel="noopener">自监督学习和对比学习 (qq.com)</a>
</p>
<p>文中提到对准确率提升最多的一些增强方式是如下的三种：</p>
<ul>
<li>Crop，Resize ，Flip</li>
<li>Colour Distortion</li>
<li>Gaussian Blur</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">torchvision</span> <span class="kn">import</span> <span class="n">transforms</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Size used in SimCLR</span>
</span></span><span class="line"><span class="cl"><span class="n">size</span> <span class="o">=</span> <span class="mi">224</span>
</span></span><span class="line"><span class="cl"><span class="n">crop_resize_flip</span> <span class="o">=</span> <span class="n">transforms</span><span class="o">.</span><span class="n">Compose</span><span class="p">([</span><span class="n">transforms</span><span class="o">.</span><span class="n">RandomResizedCrop</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="n">scale</span><span class="o">=</span><span class="p">(</span><span class="mf">0.08</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">),</span> <span class="n">ratio</span><span class="o">=</span><span class="p">(</span><span class="mi">3</span><span class="o">/</span><span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="o">/</span><span class="mi">3</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">                                       <span class="n">transforms</span><span class="o">.</span><span class="n">RandomHorizontalFlip</span><span class="p">(</span><span class="n">p</span><span class="o">=</span><span class="mf">0.5</span><span class="p">)])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Higher means stronger </span>
</span></span><span class="line"><span class="cl"><span class="n">s</span> <span class="o">=</span> <span class="mf">1.0</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 0.8*s and 0.2*s are from the paper</span>
</span></span><span class="line"><span class="cl"><span class="n">colour_jitter</span> <span class="o">=</span> <span class="n">transforms</span><span class="o">.</span><span class="n">ColorJitter</span><span class="p">(</span><span class="n">brightness</span><span class="o">=</span><span class="mf">0.8</span><span class="o">*</span><span class="n">s</span><span class="p">,</span> <span class="n">contrast</span><span class="o">=</span><span class="mf">0.8</span><span class="o">*</span><span class="n">s</span><span class="p">,</span> <span class="n">saturation</span><span class="o">=</span><span class="mf">0.8</span><span class="o">*</span><span class="n">s</span><span class="p">,</span> <span class="n">hue</span><span class="o">=</span><span class="mf">0.2</span><span class="o">*</span><span class="n">s</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">colour_jitter</span> <span class="o">=</span> <span class="n">transforms</span><span class="o">.</span><span class="n">RandomApply</span><span class="p">([</span><span class="n">colour_jitter</span><span class="p">],</span> <span class="n">p</span><span class="o">=</span><span class="mf">0.8</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">colour_distortion</span> <span class="o">=</span> <span class="n">transforms</span><span class="o">.</span><span class="n">Compose</span><span class="p">([</span><span class="n">colour_jitter</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                                        <span class="n">transforms</span><span class="o">.</span><span class="n">RandomGrayscale</span><span class="p">(</span><span class="n">p</span><span class="o">=</span><span class="mf">0.2</span><span class="p">)])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">kernel_size</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="mf">0.1</span><span class="o">*</span><span class="n">size</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># The size of the kernel must be odd</span>
</span></span><span class="line"><span class="cl"><span class="n">kernel_size</span> <span class="o">=</span> <span class="n">kernel_size</span> <span class="k">if</span> <span class="n">kernel_size</span><span class="o">%</span><span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span> <span class="k">else</span> <span class="n">kernel_size</span><span class="o">+</span><span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="n">gaussian_blur</span> <span class="o">=</span> <span class="n">transforms</span><span class="o">.</span><span class="n">GaussianBlur</span><span class="p">(</span><span class="n">kernel_size</span><span class="p">,</span> <span class="n">sigma</span><span class="o">=</span><span class="p">(</span><span class="mf">0.1</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">gaussian_blur</span> <span class="o">=</span> <span class="n">transforms</span><span class="o">.</span><span class="n">RandomApply</span><span class="p">([</span><span class="n">gaussian_blur</span><span class="p">],</span> <span class="n">p</span><span class="o">=</span><span class="mf">0.5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                                       
</span></span><span class="line"><span class="cl"><span class="n">augment</span> <span class="o">=</span> <span class="n">transforms</span><span class="o">.</span><span class="n">Compose</span><span class="p">([</span><span class="n">crop_resize_flip</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                              <span class="n">colour_distortion</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                              <span class="n">gaussian_blur</span><span class="p">])</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211118153623.png">
    <img alt="image-20211118153622239" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211118153623.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211118153623.png" style="display: block; margin: 0 auto;"
      alt="image-20211118153622239"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="早停法">早停法</h2>
<p><a href="https://microsoft.github.io/ai-edu/%E5%9F%BA%E7%A1%80%E6%95%99%E7%A8%8B/A2-%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E5%9F%BA%E6%9C%AC%E5%8E%9F%E7%90%86/en-us/Step7%20-%20DNN/16.4-%E6%97%A9%E5%81%9C%E6%B3%95.html" target="_blank" rel="noopener">MicroSoft Ai 教程 ES</a>
</p>
<p>因为准确率都不再提高了，损失值反而上升了，再继续训练也是无益的，只会浪费训练的时间。那么该做法的一个重点便是怎样才认为验证集不再提高了呢？并不是说准确率一降下来便认为不再提高了，因为可能在这个Epoch上，准确率降低了，但是随后的Epoch准确率又升高了，所以不能根据一两次的连续降低就判断不再提高。</p>
<p>对模型进行训练的过程即是对模型的参数进行学习更新的过程，这个参数学习的过程往往会用到一些迭代方法，如梯度下降（Gradient descent）学习算法。Early stopping便是一种迭代次数截断的方法来防止过拟合的方法，即在模型对训练数据集迭代收敛之前停止迭代来防止过拟合。</p>
<p>更好的一个方式应该是使用一个类来进行计数</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">TrainingTrace</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">	<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">need_earlystop</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">patience</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">mode</span><span class="o">=</span><span class="s1">&#39;max&#39;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">		<span class="bp">self</span><span class="o">.</span><span class="n">early_stop</span> <span class="o">=</span> <span class="n">need_earlystop</span>
</span></span><span class="line"><span class="cl">		<span class="bp">self</span><span class="o">.</span><span class="n">patience</span> <span class="o">=</span> <span class="n">patience</span>
</span></span><span class="line"><span class="cl">		<span class="bp">self</span><span class="o">.</span><span class="n">patience_count</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">		<span class="bp">self</span><span class="o">.</span><span class="n">last_vid_metrric</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="s1">&#39;inf&#39;</span><span class="p">)</span> <span class="k">if</span> <span class="n">model</span> <span class="o">==</span><span class="s1">&#39;min&#39;</span> <span class="k">else</span> <span class="nb">float</span><span class="p">(</span><span class="s1">&#39;-inf&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="bp">self</span><span class="o">.</span><span class="n">compare</span> <span class="o">=</span> <span class="n">new_min</span> <span class="k">if</span> <span class="n">model</span> <span class="o">==</span> <span class="s1">&#39;min&#39;</span> <span class="k">else</span> <span class="n">new_max</span>
</span></span><span class="line"><span class="cl">	
</span></span><span class="line"><span class="cl">	<span class="k">def</span> <span class="nf">step</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">		</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在得到早停的迭代次数和权重矩阵参数后，后续有几种方法可以选择。</p>
<p><strong>彻底停止</strong>
就是啥也不做了，最多再重复几次早停的试验，看看是不是稳定，然后就使用做为训练结果。</p>
<p><strong>再次训练</strong>
由于第一次早停是通过验证集计算loss值来实现的，所以这次不再分训练集和验证集，记住了早停时的迭代次数，可以重新初始化权重矩阵参数，使用所有数据再次训练，然后到达第一次的时停止。</p>
<p>但是由于样本多了，更新批次也会变多，所以可以比较两种策略：</p>
<ol>
<li>总迭代次数epoch保持不变 2) 总更新梯度的次数保持不变</li>
</ol>
<p>优点：使用更多的样本可以达到更好的泛化能力。</p>
<p>缺点：需要重新花时间训练。</p>
<p><strong>继续训练</strong>
得到后，用全部训练数据（不再分训练集和验证集），在此基础上继续训练若干轮，并且继续用以前的验证集来监控损失函数值，如果能得到比以前更低的损失值，将会是比较理想的情况。</p>
<p>优点：可以避免重新训练的成本。</p>
<p>缺点：有可能不能达到目的，损失值降不到理想位置，从而不能终止训练。</p>
<h2 id="效率优化">效率优化</h2>
<p>and there are some tips in this <a href="https://sagivtech.com/2017/09/19/optimizing-pytorch-training-code/" target="_blank" rel="noopener">article</a>
, we should read and learn about it</p>
<p>这一部分希望通过trick或者对应的一些代码技巧，优化训练过程中带来的资源占用和损耗，进一步提升训练时效性和资源上的有效利用</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># making relu inplace will save memory </span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">inplace_relu</span><span class="p">(</span><span class="n">m</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">classname</span> <span class="o">=</span> <span class="n">m</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">classname</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s1">&#39;ReLU&#39;</span><span class="p">)</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">m</span><span class="o">.</span><span class="n">inplace</span><span class="o">=</span><span class="kc">True</span>
</span></span><span class="line"><span class="cl"><span class="c1"># we need to learn this function</span>
</span></span><span class="line"><span class="cl"><span class="n">model</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">inplace_relu</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>relu(inplace = True)</p>
<h3 id="rapidai">rapidAI</h3>
<p>Thanks to Nvidia, we could using np, spicy, pandas, sklearn on CUDA, which is much more faster. Achieve this by those repo: cuml for sklearn, cupy for numpy and spicy, cudf for dataframe and so on.</p>
<p>借助这几个仓库的文档, 我们可以学习如何调用这些库去加速和实现我们的代码.</p>
<p>在这里要注意的是, 使用这几个仓库的同时会<strong>引入更多的数据类型</strong>, 以及<strong>设备存储</strong>情况, 我们要在必要的时候对数据的存储位置进行<strong>分析和迁移</strong>.</p>
<p>过于频繁的数据移动可能反而会减慢运行速度, 但是如果是后续不需要的数据我们可以进行迁移.</p>
<p><strong>Install</strong></p>
<ol>
<li>如果版本和torch的匹配(old version) 10.2 可以通过以下的命令安装cuml, 但是要注意panda版本 == 1.3.0, 首先对panda版本进行修改, 这种时候可能使用pip结合conda是一个更好的选择
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>如果版本不匹配, 我们可以首先配置rapidai的环境, 在安装pytorch即可, 或者使用nvidia发布的相同cuda版本的pytorch.</li>
</ol>
<h3 id="torchcudaamp">torch.Cuda.AMP</h3>
<p>使用Torch自带的AMP取代APEX的AMP进行优化，在&gt;=1.6的情况下，Torch已经自动支持了AMP混合, 而且事实证明在大多数情况下, Torch对amp的支持相比APEX来说要更加稳定和性能友好。</p>
<p>使用方法：
较为简单，只需要在训练的主流程中进行如下的嵌入</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">torch.cuda.amp</span> <span class="kn">import</span> <span class="n">autocast</span><span class="p">,</span> <span class="n">GradScaler</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 在训练最开始的阶段实例化一个GradScaler对象</span>
</span></span><span class="line"><span class="cl"><span class="n">scaler</span> <span class="o">=</span> <span class="n">GradScaler</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">epochs</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">	<span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="n">iterators</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="o">...</span>
</span></span><span class="line"><span class="cl">		
</span></span><span class="line"><span class="cl">		<span class="c1"># model and loss</span>
</span></span><span class="line"><span class="cl">		<span class="k">with</span> <span class="n">autocast</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">			<span class="n">out</span> <span class="o">=</span> <span class="n">model</span><span class="p">(</span><span class="nb">input</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="n">loss</span> <span class="o">=</span> <span class="n">loss_fn</span><span class="p">(</span><span class="n">output</span><span class="p">,</span> <span class="n">target</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		
</span></span><span class="line"><span class="cl">		<span class="c1"># and change the update and backward phas</span>
</span></span><span class="line"><span class="cl">		<span class="c1"># 放大loss</span>
</span></span><span class="line"><span class="cl">		<span class="n">scaler</span><span class="o">.</span><span class="n">scale</span><span class="p">(</span><span class="n">loss</span><span class="p">)</span><span class="o">.</span><span class="n">backward</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">		<span class="c1"># 对inf和nan进行判断，没有问题的话就进行step</span>
</span></span><span class="line"><span class="cl">		<span class="n">scaler</span><span class="o">.</span><span class="n">step</span><span class="p">(</span><span class="n">optimizer</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="c1"># 是否对scaler进行更新</span>
</span></span><span class="line"><span class="cl">		<span class="n">scaler</span><span class="o">.</span><span class="n">update</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">		
</span></span><span class="line"><span class="cl">		</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="apex_显存优化">APEX_显存优化</h3>
<p>this session is write for the nvidia module <a href="https://github.com/NVIDIA/apex" target="_blank" rel="noopener">APEX</a>
 which can save a lot of memory and accelerate the training speed. we should learn how to use it .</p>
<p>通过APEX好像能优化接近50%的显存，而且在修改原框架代码中的要求很小，所以在这里有必要通过APEX去优化我们的框架</p>
<p>理论参考：<a href="https://zhuanlan.zhihu.com/p/79887894" target="_blank" rel="noopener">基于Apex的混合精度加速</a>
；</p>
<p>其中<code>opt_level</code>分别表示：O0纯FP32，O1混合精度训练，O2几乎FP16除了BN，O3纯FP16很不稳定，但是速度最快</p>
<p><strong>安装</strong>：</p>
<ul>
<li>
<p>验证cuda版本，验证torch的cuda版本</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">nvcc -V
</span></span><span class="line"><span class="cl"><span class="c1"># nvcc 很可能会找不到命令，去如下路径搜索是否cuda正确安装</span>
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> /usr/local/cuda*/bin
</span></span><span class="line"><span class="cl"><span class="c1"># 其中若有nvcc命令的话可以直接执行</span>
</span></span><span class="line"><span class="cl">nvcc -V</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">torch</span> 
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">version</span><span class="o">.</span><span class="n">cuda</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>安装apex</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git clone https://github.com/NVIDIA/apex
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> apex
</span></span><span class="line"><span class="cl">pip install -v --no-cache-dir --global-option<span class="o">=</span><span class="s2">&#34;--cpp_ext&#34;</span> --global-option<span class="o">=</span><span class="s2">&#34;--cuda_ext&#34;</span> ./</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>import验证安装成功</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">apex</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
</ul>
<p><strong>使用</strong>：</p>
<p>参考官方示例，我们可以知道APEX的使用场景主要集中在几个部分：</p>
<p>model,optimizer,loss upgrade and parallel</p>
<p>故而我们对原始代码修改或添加如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">apex</span> <span class="kn">import</span> <span class="n">amp</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">apex.parallel</span> <span class="kn">import</span> <span class="n">DistributedDataParallel</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">model</span> <span class="o">=</span> <span class="n">resnet</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">optimizer</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">optim</span><span class="o">.</span><span class="n">SGD</span><span class="p">(</span><span class="n">model</span><span class="o">.</span><span class="n">parameters</span><span class="p">(),</span><span class="n">lr</span><span class="o">=</span><span class="mf">1e-3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># MODEL PART: after model and optimizer design</span>
</span></span><span class="line"><span class="cl"><span class="n">model</span><span class="p">,</span> <span class="n">optimizer</span> <span class="o">=</span> <span class="n">amp</span><span class="o">.</span><span class="n">initialize</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="n">optimizer</span><span class="p">,</span> <span class="n">opt_level</span> <span class="o">=</span> <span class="s2">&#34;O1&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># DISTRIBUTION PART:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># replace nn.parallel.DistributedDataParallel()</span>
</span></span><span class="line"><span class="cl"><span class="n">model</span> <span class="o">=</span> <span class="n">DistributedDataParallel</span><span class="p">(</span><span class="n">model</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># LOSS PART:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># replace the loss BP process</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># loss.backward()</span>
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="n">amp</span><span class="o">.</span><span class="n">scale_loss</span><span class="p">(</span><span class="n">loss</span><span class="p">,</span> <span class="n">optimizer</span><span class="p">)</span> <span class="k">as</span> <span class="n">scaled_loss</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">scaled_loss</span><span class="o">.</span><span class="n">backward</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">optimizer</span><span class="o">.</span><span class="n">step</span><span class="p">()</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>此外，如果我们希望使用APEX在训练过程中执行resume的话，我们还需要对代码做如下的添加</p>
<p>Note that we recommend restoring the model using the same <code>opt_level</code>. Also note that we recommend calling the <code>load_state_dict</code> methods after <code>amp.initialize</code>.</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># Save checkpoint</span>
</span></span><span class="line"><span class="cl"><span class="n">checkpoint</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;model&#39;</span><span class="p">:</span> <span class="n">model</span><span class="o">.</span><span class="n">state_dict</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;optimizer&#39;</span><span class="p">:</span> <span class="n">optimizer</span><span class="o">.</span><span class="n">state_dict</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;amp&#39;</span><span class="p">:</span> <span class="n">amp</span><span class="o">.</span><span class="n">state_dict</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">torch</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">checkpoint</span><span class="p">,</span> <span class="s1">&#39;amp_checkpoint.pt&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="o">...</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Restore</span>
</span></span><span class="line"><span class="cl"><span class="n">model</span> <span class="o">=</span> <span class="o">...</span>
</span></span><span class="line"><span class="cl"><span class="n">optimizer</span> <span class="o">=</span> <span class="o">...</span>
</span></span><span class="line"><span class="cl"><span class="n">checkpoint</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="s1">&#39;amp_checkpoint.pt&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">model</span><span class="p">,</span> <span class="n">optimizer</span> <span class="o">=</span> <span class="n">amp</span><span class="o">.</span><span class="n">initialize</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="n">optimizer</span><span class="p">,</span> <span class="n">opt_level</span><span class="o">=</span><span class="n">opt_level</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">model</span><span class="o">.</span><span class="n">load_state_dict</span><span class="p">(</span><span class="n">checkpoint</span><span class="p">[</span><span class="s1">&#39;model&#39;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="n">optimizer</span><span class="o">.</span><span class="n">load_state_dict</span><span class="p">(</span><span class="n">checkpoint</span><span class="p">[</span><span class="s1">&#39;optimizer&#39;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="n">amp</span><span class="o">.</span><span class="n">load_state_dict</span><span class="p">(</span><span class="n">checkpoint</span><span class="p">[</span><span class="s1">&#39;amp&#39;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Continue training</span>
</span></span><span class="line"><span class="cl"><span class="o">...</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>安装过程中遇到了很多的问题：</p>
<p><a href="https://github.com/NVIDIA/apex/issues/1043" target="_blank" rel="noopener">Build error &ldquo;fatal error: ATen/cuda/CUDAGraphsUtils.cuh: No such file or directory&rdquo; · Issue #1043 · NVIDIA/apex (github.com)</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># rollback apex to the previous commit</span>
</span></span><span class="line"><span class="cl">git reset --hard 3fe10b5597ba14a748ebb271a6ab97c09c5701ac</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>cc1plus: warning: command line option &lsquo;-Wstrict-prototypes&rsquo; is valid for C/ObjC but not for C++</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">pip install -U cpython
</span></span><span class="line"><span class="cl"><span class="c1"># this method is not useful</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>command &lsquo;gcc&rsquo; failed with exit status 1</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git checkout f3a960f80244cf9e80558ab30f7f7e8cbf03c0a0</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="限制网络的输出范围">限制网络的输出范围</h2>
<p>实际上，这一部分的应用就属于激活函数的数学理念问题了，我们倘若需要将网络的<strong>输出限制在一定的范围</strong>内，除了<strong>自己编写相关的数据处理</strong>手段之外，<strong>激活函数</strong>实际上有一部分原因就是为了这点设置的。</p>
<ol>
<li>神经网络基于对非线性运算的需要，引入了激活函数，强化了网络的学习能力；</li>
<li>同时神经网络<strong>对于输出</strong>有所要求（很多时候是以一种概率表达的方式输出的）所以就会需要softmax（0，1同时<code>sum==1</code>）之类的函数，<strong>可以将分类器的原始输出映射为概率。</strong> Sigmoid tanh之类的将输出限制在（0，1），但是并没有对加和有要求，这里可以做一个区分https://www.cnblogs.com/jins-note/p/12528412.html区分sigmoid（多分类）和Softmax（单分类）</li>
<li>Softmax和tanh可能会出现梯度消失的问题，ReLU将输出限制在（0，1）
<a href="https://zhuanlan.zhihu.com/p/73214810" target="_blank" rel="noopener">一部分激活函数的特点</a>
</li>
</ol>
<p>所以很显然，我们可以通过对于相应的激活函数的应用，来限制我们的网络输出范围。</p>
]]></content:encoded>
    </item>
    <item>
      <title>PyTorch Handbook 00 （Archive）</title>
      <link>https://aikenh.cn/posts/pytorch/</link>
      <pubDate>Wed, 15 Dec 2021 08:00:57 +0000</pubDate>
      <guid>https://aikenh.cn/posts/pytorch/</guid>
      <description>Basic Knowledge of PyTorch</description>
      <content:encoded><![CDATA[<h1 id="basic-part基础设定部分">Basic Part基础设定部分</h1>
<p>@AikenH 2020 + 2021</p>
<p>this part is about pytorch basic unit, help me to code deep learning better.</p>
<h2 id="tensor张量计算">Tensor张量计算</h2>
<h3 id="两个tensor的数乘">两个tensor的数乘</h3>
<p>计算两个tensor的矩阵乘法，注意其中的batch要相互对应，如果不考虑batch，就是另一个函数</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 简单的分析一下算法的逻辑</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 这是割裂出来batch的矩阵相乘形式</span>
</span></span><span class="line"><span class="cl"><span class="n">batch1</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">randn</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">batch2</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">randn</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">out</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">bmm</span><span class="p">(</span><span class="n">batch1</span><span class="p">,</span> <span class="n">batch2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">out</span><span class="o">.</span><span class="n">size</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="s1">&#39;&#39;&#39;output ans is
</span></span></span><span class="line"><span class="cl"><span class="s1">torch.size([10,3,5])&#39;&#39;&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 按位相乘</span>
</span></span><span class="line"><span class="cl"><span class="n">res</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">mul</span><span class="p">(</span><span class="n">batch1</span><span class="p">,</span><span class="n">batch2</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>view和permute</strong>的使用实际上都是不改变原值，要用赋值的方式去做，主要是使用方式要对，一个是按照顺序去做。</p>
<h3 id="张量命名">张量命名</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">NCHW</span> <span class="o">=</span> <span class="p">[</span><span class="err">‘</span><span class="n">N</span><span class="err">’</span><span class="p">,</span> <span class="err">‘</span><span class="n">C</span><span class="err">’</span><span class="p">,</span> <span class="err">‘</span><span class="n">H</span><span class="err">’</span><span class="p">,</span> <span class="err">‘</span><span class="n">W</span><span class="err">’</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">images</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">randn</span><span class="p">(</span><span class="mi">32</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">56</span><span class="p">,</span> <span class="mi">56</span><span class="p">,</span> <span class="n">names</span><span class="o">=</span><span class="n">NCHW</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">images</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="s1">&#39;C&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">images</span><span class="o">.</span><span class="n">select</span><span class="p">(</span><span class="s1">&#39;C&#39;</span><span class="p">,</span> <span class="n">index</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="类型转换">类型转换</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># tensor 与 nd.array进行互换</span>
</span></span><span class="line"><span class="cl"><span class="n">ndarray</span> <span class="o">=</span> <span class="n">tensor</span><span class="o">.</span><span class="n">cpu</span><span class="p">()</span><span class="o">.</span><span class="n">numpy</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">tensor</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">from_numpy</span><span class="p">(</span><span class="n">ndarray</span><span class="p">)</span><span class="o">.</span><span class="n">float</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># tensor与PIL.IMAGE进行互换</span>
</span></span><span class="line"><span class="cl"><span class="n">image</span> <span class="o">=</span> <span class="n">torchvision</span><span class="o">.</span><span class="n">transforms</span><span class="o">.</span><span class="n">functional</span><span class="o">.</span><span class="n">to_pil_image</span><span class="p">(</span><span class="n">tensor</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">path</span> <span class="o">=</span> <span class="sa">r</span><span class="s1">&#39;./figure.jpg&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">tensor</span> <span class="o">=</span> <span class="n">torchvision</span><span class="o">.</span><span class="n">transforms</span><span class="o">.</span><span class="n">functional</span><span class="o">.</span><span class="n">to_tensor</span><span class="p">(</span><span class="n">PIL</span><span class="o">.</span><span class="n">Image</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">path</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># np.ndarray 与 PIL.Image的互换</span>
</span></span><span class="line"><span class="cl"><span class="n">image</span> <span class="o">=</span> <span class="n">PIL</span><span class="o">.</span><span class="n">Image</span><span class="o">.</span><span class="n">fromarray</span><span class="p">(</span><span class="n">nd</span><span class="o">.</span><span class="n">array</span><span class="o">.</span><span class="n">astype</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">uint8</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">ndarray</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">asarray</span><span class="p">(</span><span class="n">PIL</span><span class="o">.</span><span class="n">Image</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">path</span><span class="p">))</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="维度堆叠">维度堆叠</h3>
<p>Stack，<strong>普通的维度堆叠的测试代码如下</strong></p>
<p>测试代码如下，实际上dim=0就是基本的堆起来，dim=1就是按照行来堆，dim=2就是按照列来堆</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">a</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">10</span><span class="p">)</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">b</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="mi">100</span><span class="p">,</span><span class="mi">10</span><span class="p">)</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">c</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span><span class="mi">1000</span><span class="p">,</span><span class="mi">100</span><span class="p">)</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;-----------------a----------------&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;-----------------b----------------&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">b</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;-----------------c----------------&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;-----------------dim =0----------------&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">d</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">stack</span><span class="p">((</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">,</span><span class="n">c</span><span class="p">),</span><span class="n">dim</span> <span class="o">=</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">d</span><span class="o">.</span><span class="n">shape</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;the value of d:-    </span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">d</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">]))</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">d</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 也就是说，把单个当成整体直接从上往下堆叠</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 以x[:][:]为构成单元</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;-----------------dim =1----------------&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">d</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">stack</span><span class="p">((</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">,</span><span class="n">c</span><span class="p">),</span><span class="n">dim</span> <span class="o">=</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">d</span><span class="o">.</span><span class="n">shape</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;the value of d:-    </span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">d</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">]))</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">d</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 将每个的第一个维度，按次序纳出来，同value的堆在一起</span>
</span></span><span class="line"><span class="cl"><span class="c1"># for example：[a[i][:],b[i][:],c[i][:] ]组成新的单元块</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 不，另一种理解，以x[i][:] 为单元</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;-----------------dim =2----------------&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">d</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">stack</span><span class="p">((</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">,</span><span class="n">c</span><span class="p">),</span><span class="n">dim</span> <span class="o">=</span> <span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">d</span><span class="o">.</span><span class="n">shape</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;the value of d:-    </span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">d</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">1</span><span class="p">]))</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">d</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 相应的以x[i][j]为单元构成</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>list的情况下的维度堆叠测试代码如下</strong></p>
<p>相应的测试代码如下，实际上一般是按照dim=1来进行堆叠</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">A</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">randn</span><span class="p">([</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">2</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="n">B</span> <span class="o">=</span> <span class="p">[</span><span class="n">A</span><span class="p">[:,</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">A</span><span class="o">.</span><span class="n">size</span><span class="p">(</span><span class="mi">1</span><span class="p">))]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 这样生成的是一个list,按照我们index的排序</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">A</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">B</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">C</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">stack</span><span class="p">(</span><span class="n">B</span><span class="p">,</span><span class="n">dim</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;---------------------result-----------------------&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">C</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>Cat</strong></p>
<p>实际上应该也是类似的堆叠思路</p>
<h2 id="基本的张量函数">基本的张量函数</h2>
<p>torch.split() 划分tensor</p>
<p>torch.randperm进行list的乱序处理</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 和shuffle区分，这是另一种乱序的操作</span>
</span></span><span class="line"><span class="cl"><span class="c1"># cat操作</span>
</span></span><span class="line"><span class="cl"><span class="n">a</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">a</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">tensor</span><span class="p">([</span><span class="n">i</span><span class="p">,</span><span class="n">i</span><span class="p">]))</span>
</span></span><span class="line"><span class="cl"><span class="n">all_inputs</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">cat</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># randperm的效果 test1</span>
</span></span><span class="line"><span class="cl"><span class="n">idx</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">randperm</span><span class="p">(</span><span class="n">all_inputs</span><span class="o">.</span><span class="n">size</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">idx</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">a1</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="n">all_inputs</span><span class="p">,</span> <span class="n">all_inputs</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">a1</span><span class="p">,</span><span class="n">b</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># test2 ，</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;-------------------------&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># randperm 进行list的shuffle</span>
</span></span><span class="line"><span class="cl"><span class="n">tensor_a</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">10</span><span class="p">,[</span><span class="mi">8</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;origin version &#39;</span><span class="p">,</span> <span class="n">tensor_a</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">idx</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">randperm</span><span class="p">(</span><span class="n">tensor_a</span><span class="o">.</span><span class="n">size</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;shuffle idx &#39;</span><span class="p">,</span> <span class="n">idx</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">tensor_b</span> <span class="o">=</span> <span class="n">tensor_a</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;after operation &#39;</span><span class="p">,</span> <span class="n">tensor_b</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>.fill_()按照输入的值对张量进行填充</p>
<h3 id="选取划窗">选取划窗</h3>
<p><code>nn.unfold</code>拆解卷积中的划窗步骤</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">torch</span>
</span></span><span class="line"><span class="cl"><span class="n">inputs</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">randn</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">224</span><span class="p">,</span><span class="mi">224</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">unfold</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">Unfold</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span><span class="n">stride</span><span class="o">=</span><span class="mi">4</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">output</span> <span class="o">=</span> <span class="n">unfold</span><span class="p">(</span><span class="n">inputs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># res output</span>
</span></span><span class="line"><span class="cl"><span class="n">output</span><span class="o">.</span><span class="n">size</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="err">$</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">3136</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 3136 = (224/4) * (224/4)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="torch环境设置">Torch环境设置</h2>
<h3 id="pytorch中的随机种子初始化">pytorch中的随机种子初始化</h3>
<p>yTorch 和 Python的随机数生成器就算随机种子一样也不会产生一样的结果。</p>
<p>我们可以这样来设置Pytorch的随机数种子：（通常和GPU一起使用）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">torch</span><span class="o">.</span><span class="n">manual_seed</span><span class="p">(</span><span class="n">seed</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="nnparameter">nn.parameter()</h3>
<ol>
<li>Main idea：<strong>parameter的作用，主要是将参数和model绑定在一起</strong>，我们就知道这个模型中，可能需<strong>要训练的参数</strong>有哪些，可以需要进行训练的参数加进去，但是当我们想要freeze it的时候就使用detach或者直接修改require_grad来让参数不在接受训练就好了， require_grad是其中的一个属性。可以结合上面的代码分析。</li>
<li>tensor变量是不可训练的，只有修改成parameter才能进行训练。</li>
<li>自带的网络结构中的一些weight和bias应该都是parameter的变量</li>
</ol>
<h3 id="nnsoftmax中的dim">nn.Softmax中的dim</h3>
<p>其实没那么复杂，就和数据的维度是一样的，我们需要把那一个维度的数据之后的数据全部加起来处理就用哪个维度去做。</p>
<p>IMAGE = N* DATA，dim=1 说明dim = 0 的Channel 是需要被排外的。也就是我们的softmax是基于data进行的。可以找寻源码进行进一步分析解释。</p>
<h2 id="测试验证模块">测试、验证模块</h2>
<h3 id="基本编写">基本编写</h3>
<h3 id="modeleval和modeltrain的区别">model.eval()和model.train()的区别</h3>
<p>通常在模型测试的时候会执行<code>model.eval()</code>切换模型的状态，而在训练的时候会执行<code>model.train()</code>，model在这两个状态下的区别主要有：</p>
<p>在<strong>train</strong>状态下会启用BN和Dropout，而在<strong>eval</strong>不启用这两个模块；</p>
<ul>
<li>启用BN指的是：用到每一个Batch数据的均值和方差；不启用则指的是使用整体的均值和方差（同时停止更新mean和var）</li>
<li>而对于Dropout来说：启用的时候指的是会随机进行dropout，而关闭的话就会用到全部的网络链接</li>
</ul>
<h3 id="with-torchno_grad">with torch.no_grad()</h3>
<p>上下文管理器，wrap起来的部分不会track grade</p>
<p>主要用于停止autograd模块的工作，被<code>with</code>包裹起来的部分会停止梯度的更新，得到进一步的加速把，因为我们实际上在验证的时候不会执行<code>step()</code>等操作，所以能够节省计算模型梯度的时间。</p>
<h3 id="模型的保存和读取专题">模型的保存和读取专题</h3>
<p>@Aiken 2020</p>
<p>基于onenote笔记，我们知道关键在于如何自由的读取模型中的参数，并选择性的取出来。</p>
<p><a href="https://blog.csdn.net/LXX516/article/details/80124768" target="_blank" rel="noopener">pytorch 模型部分参数的加载_LXX516的博客-CSDN博客_pytorch 加载部分参数</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 至少基于这样的方式我们能把模型中参数的string取出来。</span>
</span></span><span class="line"><span class="cl"><span class="n">pretrained_dict</span><span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">model_weight</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">model_dict</span><span class="o">=</span><span class="n">myNet</span><span class="o">.</span><span class="n">state_dict</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 1. filter out unnecessary keys</span>
</span></span><span class="line"><span class="cl"><span class="n">pretrained_dict</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="n">v</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">pretrained_dict</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="k">if</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">model_dict</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 2. overwrite entries in the existing state dict</span>
</span></span><span class="line"><span class="cl"><span class="n">model_dict</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">pretrained_dict</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">myNet</span><span class="o">.</span><span class="n">load_state_dict</span><span class="p">(</span><span class="n">model_dict</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h1 id="gpu相关的设置">GPU相关的设置</h1>
<p>@written by Aiken, 2020  this document is about Pytorch‘s CUDA, &amp; GPU setting.</p>
<h2 id="查看gpu状态">查看GPU状态</h2>
<h3 id="设置默认gpu设备">设置默认GPU设备</h3>
<p>一般使用GPU之前，我们需要知道系统中有多少GPU设备，因为默认的GPU设备是0，而且，大家一般都直接使用这张卡，所以我们如果只使用单卡的话，切换一下默认的GPU设备，能够避免一定的冲突。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 查看GPU使用状态</span>
</span></span><span class="line"><span class="cl">$ nvidia-smi
</span></span><span class="line"><span class="cl"><span class="c1"># or</span>
</span></span><span class="line"><span class="cl">$ gpustat <span class="o">[</span>--watch<span class="o">]</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="设备基本信息"><strong>设备基本信息</strong></h3>
<ol>
<li>
<p>查看是否存在GPU，数量，类型</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">torch</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 查看是否存在GPU，数量，类型</span>
</span></span><span class="line"><span class="cl"><span class="n">torch</span><span class="o">.</span><span class="n">cuda</span><span class="o">.</span><span class="n">is_available</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">torch</span><span class="o">.</span><span class="n">cuda</span><span class="o">.</span><span class="n">device_count</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">torch</span><span class="o">.</span><span class="n">cuda</span><span class="o">.</span><span class="n">get_device_name</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>查看指定的GPU的容量和名称</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">torch</span><span class="o">.</span><span class="n">cuda</span><span class="o">.</span><span class="n">get_device_capability</span><span class="p">(</span><span class="n">device</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">torch</span><span class="o">.</span><span class="n">cuda</span><span class="o">.</span><span class="n">get_device_name</span><span class="p">(</span><span class="n">device</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>设置当前系统的默认gpu_devices，推荐使用os来设置（实际上是命令行中的操作）实际上是系统设定针对当前进程的可见GPU，其他的GPU会对当前的程序隐藏，所以默认的0</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s1">&#39;CUDA_VISIBLE_DEVICES&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&#34;id&#34;</span> <span class="c1">#推荐用法</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 可以在vscode的launch.json中设置env</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>注意事项：该命令需要在所有调用了CUDA的代码、子程序之前，包括<code>import</code>，所以很多代码的import都是在main()中的。</strong></p>
</li>
</ol>
<h2 id="gpu使用率优化注意事项">GPU使用率优化（注意事项）</h2>
<h3 id="缓存爆炸问题">缓存爆炸问题</h3>
<p>GPU使用途中需要注意的地方，在每次iteration之后记得<strong>清除在GPU中占用</strong>的memory，cache等，不然有时候会导致缓存和内存的递增和爆炸。</p>
<p>具体操作：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">torch</span><span class="o">.</span><span class="n">cuda</span><span class="o">.</span><span class="n">empty_cache</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1"># after every iteration</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="运行效率优化">运行效率优化</h3>
<p><code>cudnn.benchmark</code>、<a href="https://discuss.pytorch.org/t/what-does-torch-backends-cudnn-benchmark-do/5936" target="_blank" rel="noopener">pytorch论坛</a>
 <a href="https://www.pytorchtutorial.com/when-should-we-set-cudnn-benchmark-to-true/" target="_blank" rel="noopener">pytorch中文网</a>
、<a href="https://zhuanlan.zhihu.com/p/73711222" target="_blank" rel="noopener">zhihu究极分析文</a>
</p>
<p><strong>基本使用思路</strong>：</p>
<p>在程序的开始，让cudnn花费一点额外的时间，找到适用于当前配置的最佳算法，从而优化运行效率。</p>
<p><strong>注意事项：</strong></p>
<p>但是如果我们的input_size在每个iteration都存在变化的话，那么每一个iteration都要执行一次搜索，反而得不偿失。</p>
<p><strong>具体操作</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">torch</span><span class="o">.</span><span class="n">backends</span><span class="o">.</span><span class="n">cudnn</span><span class="o">.</span><span class="n">benchmark</span> <span class="o">=</span> <span class="n">true</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="设置使用gpu的方式">设置使用GPU的方式</h3>
<h3 id="设置相应的随机种子">设置相应的随机种子</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">torch</span><span class="o">.</span><span class="n">cuda</span><span class="o">.</span><span class="n">empty_cache</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1"># part2 设置随机种子</span>
</span></span><span class="line"><span class="cl"><span class="n">torch</span><span class="o">.</span><span class="n">cuda</span><span class="o">.</span><span class="n">manual_seed</span><span class="p">(</span><span class="n">seed</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">torch</span><span class="o">.</span><span class="n">cuda</span><span class="o">.</span><span class="n">manual_seed_all</span><span class="p">(</span><span class="n">seed</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="cuda转换">CUDA转换</h3>
<p>使用<code>.cuda()</code>来对<code>模型</code>，<code>数据</code>，<code>Loss</code>进行赋值，或者使用<code>to_devices()</code>来设置到相应的GPU设备</p>
<p>将模型转化到cuda中要在优化器的建立之前执行，因为optimizer是对于模型建立的，对模型执行cuda后已经和原本的参数和模型都不是同一个了，所以一定<strong>要在建立优化器之前就对模型进行Cuda 的转化</strong>。</p>
<p>是否要对loss转换到CUDA，取决于一下的两种情况：</p>
<ul>
<li>损失函数是Functional：这样的话只要传入的参数是CUDA的就会再CUDA上计算</li>
<li>损失函数是Class with params：如果类内有参数的话，也要转换到CUDA才能一起在CUDA上计算</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">if</span> <span class="n">torch</span><span class="o">.</span><span class="n">cuda</span><span class="o">.</span><span class="n">is_available</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">	<span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="n">loss</span> <span class="o">=</span> <span class="n">loss</span><span class="o">.</span><span class="n">cuda</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">	<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="nb">print</span><span class="p">(</span><span class="s1">&#39;the loss is not cuda-able </span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">loss</span><span class="p">)))</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="多gpu并行">多GPU并行</h3>
<p>主要使用的命令<code>nn.DataParallel()</code></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">model</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">DataParaller</span><span class="p">(</span><span class="n">model</span><span class="p">,</span><span class="n">device_ids</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 如果不设定id的话，应该是自动指定全部可见的GPU的</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h1 id="cpu">CPU</h1>
<p>偶然会由于<code>pin_memory</code> 的设置来致使CPU的不正常运行（满载等等），并非总是这样。</p>
<h2 id="核心和线程数设置">核心和线程数设置</h2>
<p><a href="https://blog.csdn.net/lei_qi/article/details/115358703" target="_blank" rel="noopener">限制或增加pytorch的线程个数！指定核数或者满核运行Pytorch！！！_lei_qi的博客-CSDN博客</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">os</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">multiprocessing</span> <span class="kn">import</span> <span class="n">cpu_count</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 设置环境变量来控制线程多发的情况</span>
</span></span><span class="line"><span class="cl"><span class="n">cpu_num</span> <span class="o">=</span> <span class="n">cpu_count</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 核心代码</span>
</span></span><span class="line"><span class="cl"><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s1">&#39;OMP_NUM_THREADS&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">cpu_num</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 下面这些应该是不一定药有</span>
</span></span><span class="line"><span class="cl"><span class="n">os</span><span class="o">.</span><span class="n">environ</span> <span class="p">[</span><span class="s1">&#39;OPENBLAS_NUM_THREADS&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">cpu_num</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">os</span><span class="o">.</span><span class="n">environ</span> <span class="p">[</span><span class="s1">&#39;MKL_NUM_THREADS&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">cpu_num</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">os</span><span class="o">.</span><span class="n">environ</span> <span class="p">[</span><span class="s1">&#39;VECLIB_MAXIMUM_THREADS&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">cpu_num</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">os</span><span class="o">.</span><span class="n">environ</span> <span class="p">[</span><span class="s1">&#39;NUMEXPR_NUM_THREADS&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">cpu_num</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 从其他资料中可以感觉这条代码应该是和核心代码一样的功能，所以两个写一个应该就可以了</span>
</span></span><span class="line"><span class="cl"><span class="n">torch</span><span class="o">.</span><span class="n">set_num_threds</span><span class="p">(</span><span class="n">cpu_num</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h1 id="网络定义模块">网络定义模块</h1>
<h2 id="数据定义模块">数据定义模块</h2>
<h3 id="利用torchvision读取本地数据">利用TorchVision读取本地数据</h3>
<p><code>torchvision.datasets.imagefolder()</code> 这个函数实际上能代替我们之前写的函数，但是由于自己写的有一部分统一规则可以使得我们的自定义程度很高，所以目前我们在绝大多数情况下不使用该方法来进行替代。</p>
<p>但是由于是一个重要的函数，我们在这里还是介绍一下该工具的使用方式：</p>
<h3 id="torch-自定义dataset后的使用">torch 自定义Dataset后的使用</h3>
<ol>
<li>自定义dataset的继承以及后续调用需要注意的是不能忘记将其转换成dataloaer，然后进行iter命令的执行。</li>
<li>也可以用enumerate函数来进行调用，就是记得调用的格式是什么就好</li>
<li>可以参考basicunit中的对shuffle的认知对该函数进行进一步的理解。</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 定义dataset的部分</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">RL_AET_Dataset</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">utils</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">Dataset</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="nb">super</span><span class="p">(</span><span class="n">RL_AET_Dataset</span><span class="p">,</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="k">pass</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__len__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">pass</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">__getitem</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">pass</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 声明和构建部分 要记得使用dataloader</span>
</span></span><span class="line"><span class="cl"><span class="n">train_l_dataset</span> <span class="o">=</span> <span class="n">RL_AET_Dataset</span><span class="p">(</span><span class="n">x_l</span><span class="p">,</span> <span class="n">y_l</span><span class="p">,</span> <span class="n">args</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">train_l_dataloader</span> <span class="o">=</span><span class="n">torch</span><span class="o">.</span><span class="n">utils</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">DataLoader</span><span class="p">(</span><span class="n">train_l_dataset</span><span class="p">,</span><span class="n">batch_size</span><span class="o">=</span><span class="n">args</span><span class="p">[</span><span class="s1">&#39;b_s&#39;</span><span class="p">],</span><span class="n">shuffle</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span><span class="n">num_workers</span><span class="o">=</span><span class="n">args</span><span class="p">[</span><span class="s1">&#39;num_workers&#39;</span><span class="p">],</span><span class="n">drop_last</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span><span class="n">pin_memory</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#调用迭代部分</span>
</span></span><span class="line"><span class="cl"><span class="n">labeled_loader</span> <span class="o">=</span> <span class="nb">iter</span><span class="p">(</span><span class="n">train_l_dataloader</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#all_label_info =  [*next(labeled_loader)]</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="dataloader中的transformer">Dataloader中的transformer（）：</h3>
<p><strong>疑惑解答  用compose集成的所有transform，都会应用，有个to_tensor，切to_tensor会自动转换PIL中的channel和数值范围。</strong></p>
<ol>
<li>
<p>compose中的变换组合的顺序关系</p>
<ul>
<li>PIL处理的图像变换（比如数据增强之类的方法）</li>
<li><code>to_tensor()</code></li>
<li>处理tensor的方法：<code>normalize</code></li>
</ul>
</li>
<li>
<p>示例代码</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">data_transforms</span> <span class="o">=</span> <span class="n">transforms</span><span class="o">.</span><span class="n">Compose</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">                        <span class="n">transforms</span><span class="o">.</span><span class="n">RandomResizedCrop</span><span class="p">(</span><span class="mi">224</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">                        <span class="n">transforms</span><span class="o">.</span><span class="n">RandomHorizontalFlip</span><span class="p">()</span><span class="o">.</span>
</span></span><span class="line"><span class="cl">                        <span class="n">transforms</span><span class="o">.</span><span class="n">ToTensor</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">                        <span class="n">transforms</span><span class="o">.</span><span class="n">Normalize</span><span class="p">([</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">,</span><span class="n">c</span><span class="p">],[</span><span class="n">A</span><span class="p">,</span><span class="n">B</span><span class="p">,</span><span class="n">C</span><span class="p">])])</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 然后直接加入dataset中的参数，或者是我们自定义的部分</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 在dataset中的写法如下，我们可以在自己的dataset中进行定义</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">transformer</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">img</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">transform</span><span class="p">(</span><span class="n">img</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 具体的源码细节表现如下</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">transforms</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">img</span> <span class="o">=</span> <span class="n">t</span><span class="p">(</span><span class="n">img</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">return</span> <span class="n">img</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
</ol>
<h3 id="dataloader中的参数">Dataloader中的参数</h3>
<p>shuffle机制</p>
<p>主要解决问题：</p>
<ol>
<li>是否每次调用的时候都进行随机的操作，还是只有在初始化的时候才进行随机</li>
<li>两种不同使用Dataloader的方式是否会对shuffle的方式进行区分</li>
</ol>
<p>结论：</p>
<ol>
<li>每次对dataloader进行重新调用（重新放到enumerate），或者重新定义iter，都会重新进行shuffle。</li>
</ol>
<p>num_worker</p>
<p><a href="https://www.cnblogs.com/hesse-summer/p/11343870.html" target="_blank" rel="noopener">参考资料1</a>
  参考资料2：pytorch中文文档👇</p>
<p><strong>num_workers</strong> (<em>int</em>, optional) – 用多少个子进程加载数据。0表示数据将在主进程中加载(默认: 0)
用num_worker个子进程加载数据，所以能够将数据在主进程展示还没有调用到该数据之前就将后续的数据存入RAM，所以在数据读取上会比较快，但是占用的RAM和CPU资源会比较大。</p>
<p>samples:</p>
<p><a href="https://pytorch.org/docs/stable/data.html?highlight=dataloader#torch.utils.data.DataLoader" target="_blank" rel="noopener">torch.utils.data - PyTorch 1.9.0 documentation</a>
</p>
<p><a href="https://www.cnblogs.com/marsggbo/p/11308889.html" target="_blank" rel="noopener">一文弄懂Pytorch的DataLoader, DataSet, Sampler之间的关系</a>
</p>
<p>官方的解释是：</p>
<p>sampler (Sampler or Iterable, optional) – defines the strategy to draw samples from the dataset. Can be any Iterable with <strong>len</strong> implemented. If specified, shuffle must not be specified.</p>
<p>定义从数据集（还是最开始的哪个数据集，不能是额外的数据集）中提取样本的策略：是否能通过该Method去实现Hard-Task或者像Meta-Task一样的采样过程呢？从Meta-Transfer-Learning中看来是可以的，可以学习一下它的写法。</p>
<h4 id="collate_fn">collate_fn()</h4>
<p>collate_fn的作用就是将一个batch的数据进行合并操作。默认的collate_fn是将img和label分别合并成imgs和labels，所以如果你的__getitem__方法只是返回 img, label,那么你可以使用默认的collate_fn方法,
但是如果你每次读取的数据有img, box, label等等，那么你就需要自定义collate_fn来将对应的数据合并成一个batch数据，这样方便后续的训练步骤。</p>
<ul>
<li>编写collate_fn可以参考qidong的文章主要是接受数据和标签列表，将其整合成一个矩阵的形式;</li>
<li>如果对传参有需求,可以参考<code>lambda</code>的形式或者是类定义的形式去传入</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">dataload</span> <span class="o">=</span> <span class="n">DataLoader</span><span class="p">(</span><span class="n">dataset</span><span class="p">,</span> <span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">collate_fn</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="o">**</span><span class="n">params</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">collater</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="o">**</span><span class="n">params</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">params</span> <span class="o">=</span> <span class="o">...</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">__call</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span><span class="n">datas</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># make it a batch in this function, then we will instance this class</span>
</span></span><span class="line"><span class="cl">        <span class="o">...</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">_helpful_fn</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="o">...</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>using collate_fn, we can augment the dataset more flexible.</p>
<h2 id="编写模型">编写模型</h2>
<h3 id="模型基本单元">模型基本单元</h3>
<p>nn.conv2D：</p>
<ul>
<li>kernel_size[1]应该指的是卷积核的宽（不一定都是正方形的）</li>
</ul>
<h3 id="模型参数共享">模型参数共享：</h3>
<p><a href="https://www.cnblogs.com/wwzone/articles/12917333.html" target="_blank" rel="noopener">pytorch：对比clone、detach以及copy_等张量复制操作</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 假设有modela和modelb，我们需要在进行下降的时候执行参数统一，</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">a_para</span><span class="p">,</span><span class="n">b_para</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">modela</span><span class="o">.</span><span class="n">parameters</span><span class="p">(),</span><span class="n">modelb</span><span class="o">.</span><span class="n">parameters</span><span class="p">()):</span>
</span></span><span class="line"><span class="cl">        <span class="n">b_para</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">copy_</span><span class="p">(</span><span class="n">a_para</span><span class="o">.</span><span class="n">data</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="网络定义的方式对比分析">网络定义的方式对比分析</h3>
<p>@Aiken 2021 主要对比的是ModuleList和Sequtial</p>
<p>**结论：**通常使用的话，这里我个人推荐使用的是<code>sequtial</code>结合<code>collection</code>中的<code>orderdict</code>来构建的方法，这个方法集成了内部的<code>forward</code>，同时通过``orderdict`也能给print带来更好的可视化效果。</p>
<p>但是还是有一些特殊的使用场景我们会用到<code>ModuleList</code></p>
<p><a href="https://zhuanlan.zhihu.com/p/75206669" target="_blank" rel="noopener">详解PyTorch中的ModuleList和Sequential</a>
</p>
<p>主要区别：</p>
<ol>
<li>
<p>nn.Sequential内部实现了forward函数，因此可以不用写forward函数。而nn.ModuleList则没有实现内部forward函数。</p>
</li>
<li>
<p>nn.Sequential可以使用OrderedDict对每层进行命名，上面已经阐述过了；</p>
</li>
<li>
<p>nn.Sequential里面的模块按照顺序进行排列的，所以必须确保前一个模块的输出大小和下一个模块的输入大小是一致的。而nn.ModuleList 并没有定义一个网络，它只是将不同的模块储存在一起，这些模块之间并没有什么先后顺序可言。<strong>网络的执行顺序按照我们在forward中怎么编写来决定的</strong></p>
</li>
<li>
<p>有的时候网络中有很多相似或者重复的层，我们一般会考虑用 for 循环来创建它们，而不是一行一行地写，这种时候就使用ModuleList：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">net4</span><span class="p">(</span><span class="n">nn</span><span class="o">.</span><span class="n">Module</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="nb">super</span><span class="p">(</span><span class="n">net4</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="n">layers</span> <span class="o">=</span> <span class="p">[</span><span class="n">nn</span><span class="o">.</span><span class="n">Linear</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">linears</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">ModuleList</span><span class="p">(</span><span class="n">layers</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">layer</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">linears</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">x</span> <span class="o">=</span> <span class="n">layer</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">x</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">net</span> <span class="o">=</span> <span class="n">net4</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">net</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># net4(</span>
</span></span><span class="line"><span class="cl"><span class="c1">#   (linears): ModuleList(</span>
</span></span><span class="line"><span class="cl"><span class="c1">#     (0): Linear(in_features=10, out_features=10, bias=True)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#     (1): Linear(in_features=10, out_features=10, bias=True)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#     (2): Linear(in_features=10, out_features=10, bias=True)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#   )</span>
</span></span><span class="line"><span class="cl"><span class="c1"># )</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
</ol>
<p>基本使用：</p>
<ol>
<li>
<p>nn.sequential</p>
<p>可以通过list和*以及add moudle来进行迭代的定义，同时这种定义方式，会方便我们的重复注册</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">OrderedDict</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">net_seq</span><span class="p">(</span><span class="n">nn</span><span class="o">.</span><span class="n">Module</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="nb">super</span><span class="p">(</span><span class="n">net_seq</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">seq</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Sequential</span><span class="p">(</span><span class="n">OrderedDict</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">                        <span class="p">(</span><span class="s1">&#39;conv1&#39;</span><span class="p">,</span> <span class="n">nn</span><span class="o">.</span><span class="n">Conv2d</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">20</span><span class="p">,</span><span class="mi">5</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">                         <span class="p">(</span><span class="s1">&#39;relu1&#39;</span><span class="p">,</span> <span class="n">nn</span><span class="o">.</span><span class="n">ReLU</span><span class="p">()),</span>
</span></span><span class="line"><span class="cl">                          <span class="p">(</span><span class="s1">&#39;conv2&#39;</span><span class="p">,</span> <span class="n">nn</span><span class="o">.</span><span class="n">Conv2d</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span><span class="mi">64</span><span class="p">,</span><span class="mi">5</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">                       <span class="p">(</span><span class="s1">&#39;relu2&#39;</span><span class="p">,</span> <span class="n">nn</span><span class="o">.</span><span class="n">ReLU</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">                       <span class="p">]))</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">seq</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">net_seq</span> <span class="o">=</span> <span class="n">net_seq</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">net_seq</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#net_seq(</span>
</span></span><span class="line"><span class="cl"><span class="c1">#  (seq): Sequential(</span>
</span></span><span class="line"><span class="cl"><span class="c1">#    (conv1): Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1))</span>
</span></span><span class="line"><span class="cl"><span class="c1">#    (relu1): ReLU()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#    (conv2): Conv2d(20, 64, kernel_size=(5, 5), stride=(1, 1))</span>
</span></span><span class="line"><span class="cl"><span class="c1">#    (relu2): ReLU()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#  )</span>
</span></span><span class="line"><span class="cl"><span class="c1">#)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>nn.ModuleList:与python自带的List不同的地方在于他会自动将网络注册到Parameter中，成为网络，但是需要自己去编写forward过程</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">net_modlist</span><span class="p">(</span><span class="n">nn</span><span class="o">.</span><span class="n">Module</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="nb">super</span><span class="p">(</span><span class="n">net_modlist</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">modlist</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">ModuleList</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">                       <span class="n">nn</span><span class="o">.</span><span class="n">Conv2d</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">5</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">                       <span class="n">nn</span><span class="o">.</span><span class="n">ReLU</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">                        <span class="n">nn</span><span class="o">.</span><span class="n">Conv2d</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="mi">64</span><span class="p">,</span> <span class="mi">5</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">                        <span class="n">nn</span><span class="o">.</span><span class="n">ReLU</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">                        <span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">modlist</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">x</span> <span class="o">=</span> <span class="n">m</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">x</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">net_modlist</span> <span class="o">=</span> <span class="n">net_modlist</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">net_modlist</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#net_modlist(</span>
</span></span><span class="line"><span class="cl"><span class="c1">#  (modlist): ModuleList(</span>
</span></span><span class="line"><span class="cl"><span class="c1">#    (0): Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1))</span>
</span></span><span class="line"><span class="cl"><span class="c1">#    (1): ReLU()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#    (2): Conv2d(20, 64, kernel_size=(5, 5), stride=(1, 1))</span>
</span></span><span class="line"><span class="cl"><span class="c1">#    (3): ReLU()</span>
</span></span><span class="line"><span class="cl"><span class="c1">#  )</span>
</span></span><span class="line"><span class="cl"><span class="c1">#)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">param</span> <span class="ow">in</span> <span class="n">net_modlist</span><span class="o">.</span><span class="n">parameters</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">param</span><span class="o">.</span><span class="n">data</span><span class="p">),</span> <span class="n">param</span><span class="o">.</span><span class="n">size</span><span class="p">())</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&lt;class &#39;torch.Tensor&#39;&gt; torch.Size([20, 1, 5, 5])</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&lt;class &#39;torch.Tensor&#39;&gt; torch.Size([20])</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&lt;class &#39;torch.Tensor&#39;&gt; torch.Size([64, 20, 5, 5])</span>
</span></span><span class="line"><span class="cl"><span class="c1">#&lt;class &#39;torch.Tensor&#39;&gt; torch.Size([64])</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
</ol>
<h3 id="detach--detach_">Detach &amp; detach_</h3>
<p>这个模块在后续进行pretrain或者transfer的时候应该会经常被用到，所以这种方法还是需要熟练掌握的</p>
<p><a href="https://www.cnblogs.com/wanghui-garcia/p/10677071.html" target="_blank" rel="noopener">详细的分析介绍</a>
</p>
<p><code>detach</code>是产生一组不需要下降的“<code>Copy</code>”：如果要修改原值的话就要进行赋值操作。</p>
<p><code>detach_</code>则是修改本身参数的属性（<code>require_grad</code>etc.）执行函数就能将参数修改为不需要下降的情况，不需要执行赋值处理。</p>
<h3 id="模型调用的tips">模型调用的Tips</h3>
<p><strong>使用list进行多模型的混合调用</strong></p>
<p>由于python默认的是引用赋值，也就是浅拷贝的方式？
通过list来进行模型的批量构建，通过list来将模型整合起来，是<strong>不会</strong>使用<strong>额外的存储空间</strong>的，它们指向同一个地址。基于这样的假设，我们可以基于list来简化代码，通过LOOP来执行，相关的调用操作，比如生成器或者预测之类的，来<strong>简化</strong>代码结构。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">model1</span> <span class="o">=</span> <span class="n">AET_model</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">model2</span> <span class="o">=</span> <span class="n">AET_model</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">model_list</span> <span class="o">=</span> <span class="p">[</span><span class="n">model1</span><span class="p">,</span><span class="n">model2</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="nb">id</span><span class="p">(</span><span class="n">model1</span><span class="p">)</span><span class="o">==</span><span class="nb">id</span><span class="p">(</span><span class="n">model2</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;the address of those model is same, so donot need extra space&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 具体可以简化什么类型的操作：</span>
</span></span><span class="line"><span class="cl"><span class="n">optimizer_list</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">models_t</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">model_list</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">optimizer_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">optim</span><span class="o">.</span><span class="n">SGD</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                            <span class="n">models_t</span><span class="o">.</span><span class="n">parameters</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">                            <span class="n">lr</span><span class="p">,</span><span class="n">mom</span><span class="err">，</span><span class="n">wd</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">optimizer1</span> <span class="o">=</span> <span class="n">_</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">optimizer2</span> <span class="o">=</span> <span class="n">_</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># like this</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="warm-up-factor">Warm-up factor</h3>
<p>对于这一部分的概念我还是有些不了解，是否和冷启动和热启动的概念是相关的，如果不是的话，顺便就学习一下冷启动和热启动的概念。</p>
<p>具体解析：</p>
<ol>
<li><a href="https://stackoverflow.com/questions/55933867/what-does-learning-rate-warm-up-mean" target="_blank" rel="noopener">neural network - What does &ldquo;learning rate warm-up&rdquo; mean? - Stack Overflow</a>
</li>
<li><a href="https://blog.csdn.net/qq_36387683/article/details/97265084" target="_blank" rel="noopener">关于warm_up学习率_云中寻雾的博客-CSDN博客</a>
</li>
</ol>
<p><a href="https://blog.csdn.net/xys430381_1/article/details/107468446" target="_blank" rel="noopener">pytorch学习率调整方法（warm up） ，label smooth、apex混合精度训练、梯度累加_xys430381_1的专栏-CSDN博客</a>
</p>
<p><a href="https://www.zhihu.com/question/338066667" target="_blank" rel="noopener">神经网络中 warmup 策略为什么有效；有什么理论解释么？</a>
</p>
<h3 id="weight-decayl2">Weight decay（L2）</h3>
<p>实际上就是对权重进行L2正则化，让权重衰减到更小的值，在一定程度上减少模型的过拟合问题，所以权重衰减实际上也叫L2正则化。</p>
<p>具体的数学推导后续将集成到<strong>GoodNote笔记</strong>上，将正则化单独作为一个模块去整理。</p>
<p><strong>权重衰减（L2正则化）的作用</strong></p>
<p><strong>作用：</strong> 权重衰减（L2正则化）可以避免模型过拟合问题。</p>
<p><strong>思考：</strong> L2正则化项有让w变小的效果，但是为什么w变小可以防止过拟合呢？</p>
<p><strong>原理：</strong> （1）从模型的复杂度上解释：更小的权值w，从某种意义上说，表示网络的复杂度更低，对数据的拟合更好（这个法则也叫做奥卡姆剃刀），而在实际应用中，也验证了这一点，L2正则化的效果往往好于未经正则化的效果。（2）从数学方面的解释：过拟合的时候，拟合函数的系数往往非常大，为什么？如下图所示，过拟合，就是拟合函数需要顾忌每一个点，最终形成的拟合函数波动很大。在某些很小的区间里，函数值的变化很剧烈。这就意味着函数在某些小区间里的导数值（绝对值）非常大，由于自变量值可大可小，所以只有系数足够大，才能保证导数值很大。而正则化是通过约束参数的范数使其不要太大，所以可以在一定程度上减少过拟合情况。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20201205175236273.png">
    <img alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20201205175236273.png" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20201205175236273.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20201205175236273.png" style="display: block; margin: 0 auto;"
      alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20201205175236273.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>image-20201205175236273</p>
<p>内容来自： <a href="https://blog.csdn.net/u012162613/article/details/44261657" target="_blank" rel="noopener">正则化方法：L1和L2 regularization、数据集扩增、dropout</a>
</p>
<h3 id="learning-rate-decay">Learning Rate Decay</h3>
<p>当我们选择了一个合适的lr，但是损失训练到一定程度以后就不再下降了，就在一个区间中来回动荡，可能是出现了一下的问题：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20201205175605729.png">
    <img alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20201205175605729.png" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20201205175605729.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20201205175605729.png" style="display: block; margin: 0 auto;"
      alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20201205175605729.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>image-20201205175605729</p>
<p>对这种问题的解决就是通过学习率衰减来实现的：将学习率随着训练的进行来进行衰减，这个方法就比较直观了。具体的方法描述可以在 <code>../project_note/训练参数调整策略.md</code>中找到。</p>
<p>也可以参考如下连接：<a href="https://blog.csdn.net/weixin_42662358/article/details/93732852" target="_blank" rel="noopener">详细理解pytorch的六种学习率pytorch</a>
</p>
<h2 id="损失函数">损失函数</h2>
<p>nn中自带的Loss Function比如说MSE之类的，计算出来的值本身就已经对batch取了平均值，同时我们进行交叉熵的计算的时候，我们不需要实现对他进行softmax，因为再CE中已经集成了softmax的操作。</p>
<h3 id="crossentropy交叉熵">CrossEntropy交叉熵</h3>
<p>这里会介绍一下Pytorch中的CE损失的具体实现的方法，这里给出三种方式的对比。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">torch</span>
</span></span><span class="line"><span class="cl"><span class="c1"># initial data and calculate method</span>
</span></span><span class="line"><span class="cl"><span class="n">input_x</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">randn</span><span class="p">((</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">label</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">tensor</span><span class="p">((</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">cri</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">CrossEntropyLoss</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">nll_f</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">NLLLoss</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># output softmax and logsoftmax and pred</span>
</span></span><span class="line"><span class="cl"><span class="n">softamx_x</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">softmax</span><span class="p">(</span><span class="n">input_x</span><span class="p">,</span><span class="n">dim</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">logsoftmax_x</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="n">softamx_x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;softamx_x </span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">,</span> <span class="n">softamx_x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;pre_res </span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">,</span> <span class="n">softamx_x</span><span class="o">.</span><span class="n">argmax</span><span class="p">(</span><span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;log_softamx_x </span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">,</span> <span class="n">logsoftmax_x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># calculate official ce and NLL</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;torch ce </span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">,</span><span class="n">cri</span><span class="p">(</span><span class="n">input_x</span><span class="p">,</span><span class="n">label</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;nll_cal </span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">,</span> <span class="n">nll_f</span><span class="p">(</span><span class="n">logsoftmax_x</span><span class="p">,</span><span class="n">label</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># calculate the manual ce loss we cal</span>
</span></span><span class="line"><span class="cl"><span class="n">res</span> <span class="o">=</span> <span class="p">[</span><span class="o">-</span><span class="n">logsoftmax_x</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">label</span><span class="p">[</span><span class="n">i</span><span class="p">]]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">label</span><span class="p">))]</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;manual cal </span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">,</span><span class="nb">sum</span><span class="p">(</span><span class="n">res</span><span class="p">)</span><span class="o">/</span><span class="nb">len</span><span class="p">(</span><span class="n">label</span><span class="p">))</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以发现三种方式计算出来的损失是一样的，这就说明了我们在计算的时候要记住，ce中是自己集成了softmax的操作，同时在Nll中是存在了取negative的操作的。按照这个操作手册去实现自己相应的损失函数设计</p>
<h2 id="优化器设计">优化器设计</h2>
<p>这一部分主要添加一些常见的优化器参数的设置包括SGD和Adam的对应设置，主要介绍一下设置Adam
实际上Adam的设置对于学习率来说没有那么敏感，但是我们还是要了解参数的意思才知道怎么去设置该优化器</p>
<h2 id="模型参数初始化和架构查看方法">模型参数初始化和架构查看方法</h2>
<p>实际上对参数初始化也就是需要对整体的架构进行遍历，所以这两个会归为一个子课题</p>
<p>参数的初始化方法只要使用如下的方式，无论我们采取那种定义的方式，，都能遍历到其中所包含的所有网络层</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 如果直接在网络定义的时候直接进行初始化</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">modules</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="n">nn</span><span class="o">.</span><span class="n">Conv2d</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">nn</span><span class="o">.</span><span class="n">init</span><span class="o">.</span><span class="n">kaiming_normal_</span><span class="p">(</span><span class="n">m</span><span class="o">.</span><span class="n">weight</span><span class="p">,</span><span class="n">mode</span><span class="o">=</span><span class="s1">&#39;fan_out&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="n">nn</span><span class="o">.</span><span class="n">BatchNorm2d</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">nn</span><span class="o">.</span><span class="n">init</span><span class="o">.</span><span class="n">constant_</span><span class="p">(</span><span class="n">m</span><span class="o">.</span><span class="n">weight</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">nn</span><span class="o">.</span><span class="n">init</span><span class="o">.</span><span class="n">constant_</span><span class="p">(</span><span class="n">m</span><span class="o">.</span><span class="n">bias</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 如果是在模型定义的外部的话</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">layer</span> <span class="ow">in</span> <span class="n">model</span><span class="o">.</span><span class="n">modules</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">layer</span><span class="p">,</span> <span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">Conv2d</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">      <span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">init</span><span class="o">.</span><span class="n">kaiming_normal_</span><span class="p">(</span><span class="n">layer</span><span class="o">.</span><span class="n">weight</span><span class="p">,</span><span class="n">mode</span><span class="o">=</span><span class="s1">&#39;fan_out&#39;</span><span class="p">,</span> <span class="n">nonlinearity</span><span class="o">=</span><span class="s1">&#39;relu&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="n">layer</span><span class="o">.</span><span class="n">bias</span> <span class="n">isnotNone</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      <span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">init</span><span class="o">.</span><span class="n">constant_</span><span class="p">(</span><span class="n">layer</span><span class="o">.</span><span class="n">bias</span><span class="p">,</span> <span class="n">val</span><span class="o">=</span><span class="mf">0.0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">layer</span><span class="p">,</span> <span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">BatchNorm2d</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">      <span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">init</span><span class="o">.</span><span class="n">constant_</span><span class="p">(</span><span class="n">layer</span><span class="o">.</span><span class="n">weight</span><span class="p">,</span> <span class="n">val</span><span class="o">=</span><span class="mf">1.0</span><span class="p">)</span> <span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">init</span><span class="o">.</span><span class="n">constant_</span><span class="p">(</span><span class="n">layer</span><span class="o">.</span><span class="n">bias</span><span class="p">,</span> <span class="n">val</span><span class="o">=</span><span class="mf">0.0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">layer</span><span class="p">,</span> <span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">Linear</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">      <span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">init</span><span class="o">.</span><span class="n">xavier_normal_</span><span class="p">(</span><span class="n">layer</span><span class="o">.</span><span class="n">weight</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="n">layer</span><span class="o">.</span><span class="n">bias</span> <span class="n">isnotNone</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">      <span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">init</span><span class="o">.</span><span class="n">constant_</span><span class="p">(</span><span class="n">layer</span><span class="o">.</span><span class="n">bias</span><span class="p">,</span> <span class="n">val</span><span class="o">=</span><span class="mf">0.0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="n">layer</span><span class="o">.</span><span class="n">weight</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">Parameter</span><span class="p">(</span><span class="n">tensor</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 也可以使用其他的方法比如parameters，children</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="childrenmodulesparameters">children、modules、parameters：</h3>
<p><code>model.modules</code>会遍历model中所有的子层，而<code>children</code>只会遍历当前层，也就是最外层的情况，所以如果要进行参数的初始化的话，最好是用类内或者类外的两种方法来实现初始化</p>
<p><code>parameter</code>返回的是模型的所有参数，所以初始化最好使用的是``modules`，而parameter一般用来初始化参数</p>
<p><strong>用numel与parameters计算参数的个数</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1">#可以简洁的写成下面的形式</span>
</span></span><span class="line"><span class="cl"><span class="c1">#numel()函数本身的作用是返回数组中元素的个数</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">count_parameters</span><span class="p">(</span><span class="n">model</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">sum</span><span class="p">(</span><span class="n">P</span><span class="o">.</span><span class="n">numel</span><span class="p">()</span> <span class="k">for</span> <span class="n">P</span> <span class="ow">in</span> <span class="n">model</span><span class="o">.</span><span class="n">parameters</span><span class="p">()</span> <span class="k">if</span> <span class="n">P</span><span class="o">.</span><span class="n">requires_grad</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#帮助理解的结构形式可以表达如下：</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">count_parameters</span><span class="p">(</span><span class="n">model</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">model</span><span class="o">.</span><span class="n">parameters</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">requires_grad</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">ans</span> <span class="o">+=</span> <span class="n">p</span><span class="o">.</span><span class="n">numel</span><span class="p">()</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="初始化原则继续调研">初始化原则：（继续调研）</h3>
<p><a href="https://blog.csdn.net/ys1305/article/details/94332007" target="_blank" rel="noopener">pytorch中的参数初始化方法总结_ys1305的博客-CSDN博客_pytorch 参数初始化</a>
</p>
<p><strong>Batch-Normalization</strong>：<a href="https://www.cnblogs.com/shine-lee/p/11989612.html" target="_blank" rel="noopener">Batch Normalization详解 - shine-lee - 博客园 (cnblogs.com)</a>
</p>
<ul>
<li>conv：<code>kaming_normal_</code></li>
<li>fc：<code>constan_,xvaier</code></li>
<li>bn：<code>normal_\constant|</code></li>
</ul>
<h3 id="典型的参数初始化方法">典型的参数初始化方法</h3>
<p>EnAET中可以看到参考的源码如下，需要注意的是，BN中只有两个参数，所以不需要进行参数的初始化，或者直接置0、1即可.</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">modules</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="n">nn</span><span class="o">.</span><span class="n">Conv2d</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 计算参数</span>
</span></span><span class="line"><span class="cl">        <span class="n">n</span> <span class="o">=</span> <span class="n">m</span><span class="o">.</span><span class="n">kernel_size</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">m</span><span class="o">.</span><span class="n">kernel_size</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="n">m</span><span class="o">.</span><span class="n">out_channels</span>
</span></span><span class="line"><span class="cl">        <span class="n">m</span><span class="o">.</span><span class="n">weight</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">normal_</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="mf">2.</span> <span class="o">/</span> <span class="n">n</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="n">nn</span><span class="o">.</span><span class="n">BatchNorm2d</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">m</span><span class="o">.</span><span class="n">weight</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">fill_</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">m</span><span class="o">.</span><span class="n">bias</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">zero_</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="n">nn</span><span class="o">.</span><span class="n">Linear</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">nn</span><span class="o">.</span><span class="n">init</span><span class="o">.</span><span class="n">xavier_normal_</span><span class="p">(</span><span class="n">m</span><span class="o">.</span><span class="n">weight</span><span class="o">.</span><span class="n">data</span><span class="p">)</span>    <span class="c1"># what&#39;s this method</span>
</span></span><span class="line"><span class="cl">        <span class="n">m</span><span class="o">.</span><span class="n">bias</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">zero_</span><span class="p">()</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="数据类型和维度">数据类型和维度</h2>
<p>在算法编写的过程中，数据的类型和维度的对齐和channel是很重要的，在这里也很容易出现很多的bug，在这里做一个信息的汇总</p>
<h3 id="输入数据的通道">输入数据的通道</h3>
<p>结论：pytorch网络输入图片的shape要求通道是<strong>channel_first</strong>（通道在前）的，所以如果我们的图片不是这样的话，我们就需要执行相应的变化。</p>
<p>TODO：整理各种数据读取方式读入的channel first 或是 last : skimage,PIL,numpy</p>
<p>整理相应的各种数据类型进行transpose（numpy）的方式</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 也可以使用view函数，但是相应的，view需要计算出各个维度相应的数值</span>
</span></span><span class="line"><span class="cl"><span class="c1"># view（）直接使用的时候不改变原值的大小，permute也不改变，使用的方法不同而已</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="n">img</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="mi">3</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">img</span> <span class="o">=</span> <span class="n">img</span><span class="o">.</span><span class="n">permute</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="标签的形式转换one-hot">标签的形式转换one-hot</h3>
<p>进行训练之前要将数据转化为onehot的形式，才能输入训练，而且一般因为是batch_size的形式，所以我们需要转化为矩阵形式的onehot，不能用单个label的转化方法。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">make_onehot_single</span><span class="p">(</span><span class="n">num</span><span class="p">,</span><span class="n">index</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;&#39;&#39;根据类别数量和index生成single，onehot&#39;&#39;&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># BTW：scatter方法也能生成one-hot</span>
</span></span><span class="line"><span class="cl">    <span class="n">onehot</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">zeros</span><span class="p">(</span><span class="n">num</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">onehot</span><span class="p">[</span><span class="n">index</span><span class="p">]</span> <span class="o">=</span> <span class="mf">1.0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">onehot</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 主要是下面这种方法需要掌握，</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">make_onehot_array</span><span class="p">(</span><span class="n">width</span><span class="p">,</span><span class="n">target</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;&#39;&#39;根据label生成onehot矩阵。
</span></span></span><span class="line"><span class="cl"><span class="s1">    width：类别数 target：具体的labeldata&#39;&#39;&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">length</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">target</span><span class="o">.</span><span class="n">view</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;the type of target is </span><span class="si">{}</span><span class="s1"> &#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">target</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="n">target</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span><span class="s1">&#39;break down&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">onehot</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">zeros</span><span class="p">(</span><span class="n">length</span><span class="p">,</span> <span class="n">width</span><span class="p">)</span><span class="o">.</span><span class="n">scatter_</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="n">target</span><span class="o">.</span><span class="n">view</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">),</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">onehot</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h1 id="visualize-可视化部分">Visualize 可视化部分</h1>
<h2 id="tensorboard-in-pytorch">Tensorboard in Pytorch</h2>
<p>@Aiken H 2021 review  之前这一部分的projection和model都没有成功显示，这次在新框架中展示一下。</p>
<p><a href="https://pytorch.org/tutorials/intermediate/tensorboard_tutorial.html" target="_blank" rel="noopener">Visualizing Models, Data, and Training with TensorBoard - PyTorch Tutorials 1.8.1+cu102 documentation</a>
</p>
<p><a href="https://blog.csdn.net/bigbennyguo/article/details/87956434" target="_blank" rel="noopener">详解PyTorch项目使用TensorboardX进行训练可视化_浅度寺-CSDN博客_tensorboardx</a>
</p>
<p><a href="https://pytorch.apachecn.org/#/docs/1.7/17?id=%e4%bd%bf%e7%94%a8-tensorboard-%e5%8f%af%e8%a7%86%e5%8c%96%e6%a8%a1%e5%9e%8b%ef%bc%8c%e6%95%b0%e6%8d%ae%e5%92%8c%e8%ae%ad%e7%bb%83" target="_blank" rel="noopener">使用 TensorBoard 可视化模型，数据和训练 (apachecn.org)</a>
</p>
<p>在pytorch教程中的Projection可以结合后续输出的Feature使用来分析相应的聚类和分类可靠性</p>
<p>可以尝试使用，教程写的很简单易懂。</p>
<h3 id="histogram-直方图参数统计">Histogram 直方图参数统计</h3>
<p>一般来说用来统计模型中间的一些参数的分布情况，具体的使用在训练的epoch之间，和val是一个比较类似的机制，具体的代码样例如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># visualize those parameter as historgram</span>
</span></span><span class="line"><span class="cl"><span class="c1"># we can add other model here</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">10</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">name</span><span class="p">,</span><span class="n">param</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">main_model</span><span class="o">.</span><span class="n">named_parameters</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">writer</span><span class="o">.</span><span class="n">add_histogram</span><span class="p">(</span><span class="s1">&#39;main_model&#39;</span><span class="o">+</span><span class="n">name</span><span class="p">,</span><span class="n">param</span><span class="o">.</span><span class="n">clone</span><span class="p">()</span><span class="o">.</span><span class="n">cpu</span><span class="p">()</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">numpy</span><span class="p">(),</span><span class="n">i</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">pass</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="embedding-projection">Embedding Projection</h3>
<p>@Aiken H 2021 这一部分可能才是神经网络的特征分布的可视化图。</p>
<p>下面这个是Google的Embedding Projection，需要上传.tsv保存的数据，但是实际上就是Tensorboard上也有集成的功能</p>
<p><a href="http://projector.tensorflow.org/" target="_blank" rel="noopener">Embedding projector - visualization of high-dimensional data</a>
</p>
<p><a href="https://www.tensorflow.org/tensorboard/tensorboard_projector_plugin" target="_blank" rel="noopener">Visualizing Data using the Embedding Projector in TensorBoard</a>
</p>
<h3 id="pr_curve">PR_CURVE</h3>
<p>这里会贴上pr_curve中需要的参数和我们这边编写的示例代码</p>
<h3 id="add_text">Add_TEXT</h3>
<p>换行失效问题, 这是因为在Tensorboard中这一部分使用的是Markdown的格式, 所以在这里我们在换行符<code>\n</code>之前, 需要保留两个空格才能实现真正的换行</p>
<h3 id="add_figure">ADD_Figure</h3>
<p>有时候我们会发现我们编写的figure在step中没有全部现实出来, 这是我们可以通过启动命令来展示所有的图片</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="o">--</span><span class="n">samples_per_plugin</span> <span class="n">images</span><span class="o">=</span><span class="mi">9999</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 999 &gt; the num you want to displ</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="可视化神经网络热力图cam">可视化神经网络热力图（CAM）</h2>
<p>@Aiken2020 为了便于查看神经网络的<strong>输出</strong>，对于图像的哪一部分<strong>更加的侧重</strong>，也就是指导网络进行分类的主要是图像的哪些区域，（相应的也可以按照类似的方法查看Attention Network的效果把），就想着<strong>可视化一下CAM</strong>。看指导分类的高响应区域是否落在核心区域。</p>
<p>参考链接：</p>
<p><a href="https://blog.csdn.net/sinat_37532065/article/details/103362517" target="_blank" rel="noopener">CAM Pytorch</a>
</p>
<h3 id="算法原理">算法原理</h3>
<p>其计算方法如下图所示。对于一个CNN模型，对其最后一个featuremap做全局平均池化（GAP）计算各通道均值，然后通过FC层等映射到class score，找出argmax，<strong>计算最大的那一类的输出相对于最后一个featuremap的梯度</strong>（实际上就是最后一个map中哪些对于分类的变化其更大的作用，也就是类似权重的机制），再把这个梯度可视化到原图上即可。直观来说，就是看一下<strong>网络抽取到的高层特征的哪部分对最终的classifier影响更大</strong>。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/20191203102807477.png">
    <img alt="ImgInGIthu" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/20191203102807477.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/20191203102807477.png" style="display: block; margin: 0 auto;"
      alt="ImgInGIthu"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ul>
<li>
<p>Quote: 找到了一篇基于Keras的CAM实现，感谢：</p>
<p><a href="https://blog.csdn.net/Einstellung/article/details/82858974" target="_blank" rel="noopener">https://blog.csdn.net/Einstellung/article/details/82858974</a>
 但是我还是习惯用Pytorch一点，所以参考着改了一版Pytorch的实现。其中，有一个地方困扰了一下，因为Pytorch的自动求导机制，一般只会保存函数值对输入的导数值，而中间变量的导数值都没有保留，而此处我们需要计算输出层相对于最后一个feature map梯度，所以参考https://blog.csdn.net/qq_27061325/article/details/84728539解决了该问题。</p>
</li>
</ul>
<h3 id="代码实现">代码实现：</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">os</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">PIL</span> <span class="kn">import</span> <span class="n">Image</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">torch</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">cv2</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">draw_CAM</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="n">img_path</span><span class="p">,</span> <span class="n">save_path</span><span class="p">,</span> <span class="n">transform</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">visual_heatmap</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;&#39;&#39;
</span></span></span><span class="line"><span class="cl"><span class="s1">    绘制 Class Activation Map
</span></span></span><span class="line"><span class="cl"><span class="s1">    :param model: 加载好权重的Pytorch model
</span></span></span><span class="line"><span class="cl"><span class="s1">    :param img_path: 测试图片路径
</span></span></span><span class="line"><span class="cl"><span class="s1">    :param save_path: CAM结果保存路径
</span></span></span><span class="line"><span class="cl"><span class="s1">    :param transform: 输入图像预处理方法
</span></span></span><span class="line"><span class="cl"><span class="s1">    :param visual_heatmap: 是否可视化原始heatmap（调用matplotlib）
</span></span></span><span class="line"><span class="cl"><span class="s1">    :return:
</span></span></span><span class="line"><span class="cl"><span class="s1">    &#39;&#39;&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># 图像加载&amp;预处理</span>
</span></span><span class="line"><span class="cl">    <span class="n">img</span> <span class="o">=</span> <span class="n">Image</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">img_path</span><span class="p">)</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="s1">&#39;RGB&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">transform</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">img</span> <span class="o">=</span> <span class="n">transform</span><span class="p">(</span><span class="n">img</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">img</span> <span class="o">=</span> <span class="n">img</span><span class="o">.</span><span class="n">unsqueeze</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># 获取模型输出的feature/score</span>
</span></span><span class="line"><span class="cl">    <span class="n">model</span><span class="o">.</span><span class="n">eval</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">features</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">features</span><span class="p">(</span><span class="n">img</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">output</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">classifier</span><span class="p">(</span><span class="n">features</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># 为了能读取到中间梯度定义的辅助函数</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">extract</span><span class="p">(</span><span class="n">g</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">global</span> <span class="n">features_grad</span>
</span></span><span class="line"><span class="cl">        <span class="n">features_grad</span> <span class="o">=</span> <span class="n">g</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># 预测得分最高的那一类对应的输出score</span>
</span></span><span class="line"><span class="cl">    <span class="n">pred</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">argmax</span><span class="p">(</span><span class="n">output</span><span class="p">)</span><span class="o">.</span><span class="n">item</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">pred_class</span> <span class="o">=</span> <span class="n">output</span><span class="p">[:,</span> <span class="n">pred</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">features</span><span class="o">.</span><span class="n">register_hook</span><span class="p">(</span><span class="n">extract</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">pred_class</span><span class="o">.</span><span class="n">backward</span><span class="p">()</span> <span class="c1"># 计算梯度</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">grads</span> <span class="o">=</span> <span class="n">features_grad</span>   <span class="c1"># 获取梯度</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">pooled_grads</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">nn</span><span class="o">.</span><span class="n">functional</span><span class="o">.</span><span class="n">adaptive_avg_pool2d</span><span class="p">(</span><span class="n">grads</span><span class="p">,</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># 此处batch size默认为1，所以去掉了第0维（batch size维）</span>
</span></span><span class="line"><span class="cl">    <span class="n">pooled_grads</span> <span class="o">=</span> <span class="n">pooled_grads</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">features</span> <span class="o">=</span> <span class="n">features</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># 512是最后一层feature的通道数</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">512</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">features</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="o">...</span><span class="p">]</span> <span class="o">*=</span> <span class="n">pooled_grads</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="o">...</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># 以下部分同Keras版实现</span>
</span></span><span class="line"><span class="cl">    <span class="n">heatmap</span> <span class="o">=</span> <span class="n">features</span><span class="o">.</span><span class="n">detach</span><span class="p">()</span><span class="o">.</span><span class="n">numpy</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">heatmap</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">mean</span><span class="p">(</span><span class="n">heatmap</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">heatmap</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">maximum</span><span class="p">(</span><span class="n">heatmap</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">heatmap</span> <span class="o">/=</span> <span class="n">np</span><span class="o">.</span><span class="n">max</span><span class="p">(</span><span class="n">heatmap</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># 可视化原始热力图</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">visual_heatmap</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">plt</span><span class="o">.</span><span class="n">matshow</span><span class="p">(</span><span class="n">heatmap</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">img</span> <span class="o">=</span> <span class="n">cv2</span><span class="o">.</span><span class="n">imread</span><span class="p">(</span><span class="n">img_path</span><span class="p">)</span>  <span class="c1"># 用cv2加载原始图像</span>
</span></span><span class="line"><span class="cl">    <span class="n">heatmap</span> <span class="o">=</span> <span class="n">cv2</span><span class="o">.</span><span class="n">resize</span><span class="p">(</span><span class="n">heatmap</span><span class="p">,</span> <span class="p">(</span><span class="n">img</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">img</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]))</span>  <span class="c1"># 将热力图的大小调整为与原始图像相同</span>
</span></span><span class="line"><span class="cl">    <span class="n">heatmap</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">uint8</span><span class="p">(</span><span class="mi">255</span> <span class="o">*</span> <span class="n">heatmap</span><span class="p">)</span>  <span class="c1"># 将热力图转换为RGB格式</span>
</span></span><span class="line"><span class="cl">    <span class="n">heatmap</span> <span class="o">=</span> <span class="n">cv2</span><span class="o">.</span><span class="n">applyColorMap</span><span class="p">(</span><span class="n">heatmap</span><span class="p">,</span> <span class="n">cv2</span><span class="o">.</span><span class="n">COLORMAP_JET</span><span class="p">)</span>  <span class="c1"># 将热力图应用于原始图像</span>
</span></span><span class="line"><span class="cl">    <span class="n">superimposed_img</span> <span class="o">=</span> <span class="n">heatmap</span> <span class="o">*</span> <span class="mf">0.4</span> <span class="o">+</span> <span class="n">img</span>  <span class="c1"># 这里的0.4是热力图强度因子</span>
</span></span><span class="line"><span class="cl">    <span class="n">cv2</span><span class="o">.</span><span class="n">imwrite</span><span class="p">(</span><span class="n">save_path</span><span class="p">,</span> <span class="n">superimposed_img</span><span class="p">)</span>  <span class="c1"># 将图像保存到硬盘</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="bugs">BUGs</h2>
<p>如果想要展示出所有step的图片, 我们可以在命令行里执行tensoroard的时候执行下列命令.</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">tensorboard --logdir log/cifar100_resnet18 --samples_per_plugin <span class="nv">images</span><span class="o">=</span><span class="m">999999</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h1 id="debug">DEBUG</h1>
<h2 id="1importerror-cannot-import-name-pillow_version">1.ImportError: cannot import name &lsquo;PILLOW_VERSION&rsquo;</h2>
<p>PIL版本过高，换低就可以，他不配是一个棘手的问题</p>
<p><code>pip install Pillow==6.2.2 --user</code></p>
<h2 id="2模型参数计算量统计-and-debug输出">2.模型参数&amp;计算量统计 and Debug输出</h2>
<ol>
<li>用来计算模型构建中网络的参数，空间大小，MAdd，FLOPs等指标，count_params很好写，然后剩下的计算我们交给两个第三方的库来实现：<code>torchstat</code>,<code>thop</code></li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">torchstat</span> <span class="kn">import</span> <span class="n">stat</span>
</span></span><span class="line"><span class="cl"><span class="n">stat</span><span class="p">(</span><span class="n">model</span><span class="p">,(</span><span class="mi">3</span><span class="p">,</span><span class="mi">224</span><span class="p">,</span><span class="mi">224</span><span class="p">))</span> <span class="c1">#that‘s all using it in the eval stage</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol>
<li>也可以使用<code>torchsummary</code>来查看各层输出的数据的维度数目</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">torchsummary</span> <span class="kn">import</span> <span class="n">summary</span>
</span></span><span class="line"><span class="cl"><span class="n">summary</span><span class="p">(</span><span class="n">model</span><span class="o">.</span><span class="n">cuda</span><span class="p">(),</span><span class="n">input_size</span><span class="o">=</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">224</span><span class="p">,</span><span class="mi">224</span><span class="p">),</span><span class="n">batch_size</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol>
<li>相应的Debug还可以使用<code>torchsnooper</code>进行：变量的类型和维度追踪这个模块通过<code>@xxxx</code>修饰器的方法调用在指定的method前面，能够在训练过程中输出一些<strong>参数值的类型</strong>和<strong>数值变化</strong>的较为详细的信息。个人理解的最佳使用环境是，用于调试或者监控<strong>类型之间的错误</strong>。</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 这个package如果没记错的话好像是使用装饰器的方法去进行测试</span>
</span></span><span class="line"><span class="cl"><span class="o">@...</span>
</span></span><span class="line"><span class="cl"><span class="n">method</span><span class="p">()</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="3pytorch加载预训练模型">3.PyTorch加载预训练模型</h2>
<p>具体错误：在于模型Dict中的Key和预训练model中的Key不对应，无法匹配。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>json</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="err">Unexpected</span> <span class="err">key(s)</span> <span class="err">in</span> <span class="err">state_dict:</span> <span class="s2">&#34;module.features. ...&#34;</span><span class="err">.，Expected</span> <span class="s2">&#34;.features....&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>问题分析：</p>
<p><strong>situation1</strong>：可以看到前面多了module这个str，这一般是由于其中一方使用了多GPU训练后直接保存的，也就是<code>DataParallel</code>模式下导致的不匹配问题。</p>
<p><strong>solution1</strong>： <a href="https://blog.csdn.net/qq_32998593/article/details/89343507" target="_blank" rel="noopener">参考资料</a>
</p>
<ol>
<li>
<p>load模型后去掉多余的参数在事先的时候发现这个方法还是存在问题的，并不是简单的dict封装的结构，所以没法这样简单的进行赋值处理:x:</p>
</li>
<li>
<p>用空白代替module，暂时还没尝试，但是我觉得会遇到和第一个一样的问题:x:</p>
</li>
<li>
<p>:zap:最简单的方法：加载模型后将模型进行DataParallel，再进行数据的转化，将数据进行并行化。具体的操作如下</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">model</span><span class="o">.</span><span class="n">cuda</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 将ids设置成拥有的GPU即可，但是不知道单GPU的情况可不可以实现这种情况</span>
</span></span><span class="line"><span class="cl"><span class="n">model</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">DataParallel</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="n">device_ids</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
</ol>
<p><strong>Situation2：</strong> 保存模型格式为.pth.tar，无法载入训练好的模型</p>
<p><strong>Solution2</strong>：</p>
<p>原因是因为被保存的模型是在高版本的pytorch下实现的，但是再低版本中读取的模型是.pth格式的，就会出现版本冲突。
解决方法如下👇：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 在高版本的环境中load model，然后再重新保存，保存的时候添加参数，使得保存成旧版本即可</span>
</span></span><span class="line"><span class="cl"><span class="n">torch</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">checkpoint</span><span class="p">,</span><span class="n">save_path</span><span class="p">,</span><span class="n">_use_new_zipfile_serialization</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># DONE</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>xxx is a zip archive(did you mean to use torch.jit.load()?)</strong></p>
<p>使用低版本的Torch去Load高版本（&gt;1.6）保存的模型（.pth.tar）遇到的问题,</p>
<p>这种错误，主要是模型的版本冲突。</p>
<p><strong>解决办法</strong>：在高版本的环境中，重新load模型，然后直接save，在保存的时候添加参数</p>
<p><code>torch.save(model.state_dict(),model_path,_use_new_zipfile_serialization=False)</code></p>
<p>就可以保存成.pth的模型，也能在低版本的torch环境中使用了</p>
<h2 id="4some-of-the-strides-of-a-given-numpy-array-are-negative">4.some of the strides of a given numpy array are negative.</h2>
<p>ver：torch1.2 这个问题可能会在后续的版本中被优化。</p>
<p><strong>Situation</strong>：</p>
<p><a href="https://www.cnblogs.com/devilmaycry812839668/p/13761613.html" target="_blank" rel="noopener">https://www.cnblogs.com/devilmaycry812839668/p/13761613.html</a>

问题出现在flat操作中，反向切片<code>[::-1]</code>会导致数据存储在内存上不连续，在旧版本中无法实现，对这样数据进行存储。
<strong>Solution1</strong>:
所以在执倒排切片的时候执行，<code>img2 = np.ascontiguousarray(img)</code>  使得数据在内存空间上连续。</p>
<p><strong>Solution2</strong>:</p>
<p>或者执行倒排切片的时候，直接<code>return img.copy()</code></p>
<h2 id="5读取loader的时候图像的大小不一">5.读取loader的时候图像的大小不一</h2>
<p>使用Crop对图像进行处理的时候，不注意的话就是会出现这样的问题，图像的size随机改变，导致的输出不统一。也可能是Crop函数写的有问题。</p>
<p><strong>bug info</strong>如下</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ RuntimeError: invalid argument 0: Sizes of tensors must match except in dimension 0. Got <span class="m">182</span> and <span class="m">360</span> in dimension <span class="m">2</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>Solution：</strong></p>
<p>resize，spp，padding，<strong>adaptiveMaxPooling</strong>（自适应的pooling，pooling到指定的size（channel除外））</p>
<h2 id="6bus-error-dataloader-num_worker">6.bus error dataloader num_worker</h2>
<p>原因暂时还不是太清楚，但是我们可以把num_worker设置为0 来解决这个问题.jpg</p>
<h2 id="7bus-errorinsufficient-shared-memoryshm">7.bus error：insufficient shared memory（shm）</h2>
<p>这种原因通常会在docker环境中出现，由于未指定shm容量大小，比如<code>ipc=host</code>之类的命令，就会导致docker的shm只有64m，于是在运行的时候就会出问题。这种情况下<strong>只能重新run docker</strong>（目前只找到了这个方法）。</p>
<p>如果要妥协的话，就只能<strong>试着减小batch_size</strong>。但是随着模型的设计上，这其实不是一个可以逃避的问题，也会增加莫须有的其他成本，所以。</p>
<h2 id="8训练过程中cache和memory的占用逐渐升高">8.训练过程中Cache和Memory的占用逐渐升高</h2>
<p>主要的体现是：<strong>逐渐升高</strong>这一点，而不是稳定的情况；</p>
<p>有点玄学，但是在这种情况下，我们在每个iteration结束的时候使用清楚显存的函数，竟然就能进行控制了，虽然我不知道为啥清楚显存的函数会顺便连内存中的cache也一起清除了，但是就是，学。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">torch</span><span class="o">.</span><span class="n">cuda</span><span class="o">.</span><span class="n">empty_cache</span><span class="p">()</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="9梯度爆炸问题算法没有学习效果">9.梯度爆炸问题，算法没有学习效果</h2>
<p>梯度爆炸问题，分析可能出现存在的问题：</p>
<ul>
<li>某一部分的学习参数可能的lr过高，权重过高，导致误差快速传播。</li>
<li>问题的复杂度过高，算法overpower了把。</li>
</ul>
<p>针对于第一点的话，我们参考工程笔记中的学习率调整策略即可。</p>
<p>如果是问题的复杂度过高，那么可能是问题对于我们的模型来说已经overpower的，我们可能需要去加深网络的层数，或者对网络进行进一步的设计和对数据的分析问题。</p>
<h2 id="10类型转换问题汇总">10.类型转换问题汇总</h2>
<ol>
<li>
<p>比如<code>scatter_</code>需要将数据从int32的格式转换成int64，我们要掌握一下在Pytorch中进行数据类型转换的技巧。</p>
</li>
<li>
<p><strong>Expected object of scalar type Float but got scalar type Double for argument #2 &rsquo;target&rsquo;</strong> 数据类型不匹配，一个是np.float32,另一个是64
参考解决方案：<a href="https://stackoverflow.com/questions/56741087/how-to-fix-runtimeerror-expected-object-of-scalar-type-float-but-got-scalar-typ" target="_blank" rel="noopener">重要</a>
</p>
</li>
<li>
<p><strong>Expected object of scalar type Long but got scalar type Float for argument</strong>
希望得到的是Long型标量数据，但是得到了Float型的数据（实际上可能是我们进行测试的时候使用了小数带来的，但是我们也能将其转化就是了）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">Longtensor</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="nb">type</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">longtensor</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p><strong>RuntimeError: Input type (torch.cuda.FloatTensor) and weight type (torch.DoubleTensor) should be the same</strong>
<strong>RuntimeError: Input type (torch.cuda.ByteTensor) and weight type (torch.cuda.FloatTensor) should be the same</strong>问题实际上都是和权重的数据类型不匹配，需要将字节型或者是FLoat型向Weight的数据类型转换，但是可能这里的问题实际上出现在就是我们导入的数据类型是不正确的。还是使用<code>type()</code>命令来进行数据类型的转换，但是关键还是：<strong>检查输入数据的类型以及数值范围，同时看看在进行dataloader的时候有没有指定to_tensor的变换等等</strong></p>
</li>
</ol>
<p><a href="https://www.jianshu.com/p/75dff8e7ed18" target="_blank" rel="noopener">参考资料链接</a>
</p>
<p><strong>进行数据转换的几种方式</strong></p>
<ol>
<li>
<p>使用函数<code>tensor1.type_as(tensor2)</code>将1的数据类型转换成2的数据类型。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">tensor_1</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">FloatTensor</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">tensor_2</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">IntTensor</span><span class="p">([</span><span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="n">tensor_1</span> <span class="o">=</span> <span class="n">tensor_1</span><span class="o">.</span><span class="n">type_as</span><span class="p">(</span><span class="n">tensor_2</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p><code>tensor.type(torch.IntTensor)</code></p>
</li>
<li>
<p><code>tensor.long()</code>,<code>tensor.char()</code>,<code>tensor.int()</code>,<code>tensor.byte()</code>,<code>tensor.double()</code></p>
</li>
<li>
<p><code>tenosr.to(torch.long)</code></p>
</li>
</ol>
<h2 id="11数据维度不对应问题汇总">11.数据维度不对应问题汇总</h2>
<ol>
<li>
<p><strong>multi-target not supported at</strong>问题实际上可以翻译成：维度上和交叉熵损失函数的需求不对应。在使用交叉熵损失函数的时候，target的形状应该是和label的形状一致或者是只有batchsize这一个维度的。如果target是这样的【batchszie，1】就会出现上述的错误</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">使用squeeze</span><span class="err">（）</span><span class="n">函数降低维度</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
</ol>
<h2 id="12取出具体数值时候的问题">12.取出具体数值时候的问题</h2>
<ol>
<li>**RuntimeError: Can&rsquo;t call numpy() on Variable that requires grad. Use var.detach().numpy()**对于输出的结果要转换成具体的数值的时候，如果我们后续还需要这个数值的梯度，就不能转换到<code>cpu</code>后再转换到<code>numpy</code>,就好比说，我们要取出Loss的时候，我们可以直接使用item()取出具体的数值，而不需要转到CPU<a href="#">上</a>
</li>
</ol>
<h2 id="13cpu占用99">13.CPU占用99%</h2>
<p>问题描述：使用torch自带的dataset中的cifar10的时候，在每个epoch结束的时候，CPU占用率高达99%，并不随着num_workder而改变，问题可能由于pytorch开辟了太多的线程</p>
<p><a href="https://blog.csdn.net/stay_zezo/article/details/107809409" target="_blank" rel="noopener">windows10下pytorch的GPU利用率低，占用率低_stay_zezo的博客-CSDN博客</a>
</p>
<p>可能是由于GPU运算太快了，启用了多线程进行加载数据，这种时候启用<code>pin_memory=true</code> 能起到一定的作用把，加快一点数据读取。</p>
<p>最终解决方案 ：<code>pin-memory=false</code> 反正原因很神奇，但是最终就是因为这个解决的，可能是因为memory超了，所以每次都需要重新empty_cache 重新装进页，所以反而加重了CPU的负担</p>
<h2 id="14-预测值全为0模型收敛到奇怪的地方损失保持一致全均等">14. 预测值全为0，模型收敛到奇怪的地方，损失保持一致（全均等）</h2>
<p>这种情况通常是由于模型设计中存在一点问题：</p>
<p>比如这次是由于模型中fc后面添加了relu，这样导致输出的负值全被抑制了，导致学习出现了严重的错误后果。</p>
<h2 id="15模型部分-训练中模型准确率不上升">15.模型部分： 训练中模型准确率不上升</h2>
<p>由于框架已经验证过是可以进行正常训练的，在这种情况下出现模型的准确率不上升可能是由于模型本身设计（内部代码编写）上的问题。</p>
<h2 id="16-on-entry-to-sgemm-parameter-number-8-had-an-illegal-value">16. On entry to SGEMM parameter number 8 had an illegal value</h2>
<p>Tracing failed sanity checks!
Graphs differed across invocations!</p>
<p>fc的问题，输入fc和对应的网络输入层不一致，检查阶段数目和feature输出的特征维度</p>
<h2 id="17-cuda-error-device-side-assert-triggered-cuda-kernel-errors-might-be-asynchronously-reported-at-some-other-api-call">17. CUDA error: device-side assert triggered CUDA kernel errors might be asynchronously reported at some other API call</h2>
<p>这个问题的出现的根本原因在于：</p>
<p>维度不匹配：标签的dimension 超出了全连接层最后输出的dimension，这一部分错误的触发，和Loss的计算，Acc的计算，有着强烈的相关关系。</p>
<p>为了解决这个问题，我们在训练相关的验证和训练环节，需要保持训练数据集和验证数据集在类别数目上的一致性，而在我们需要对数据集外的数据进行测试的时候，我们避免进行Loss的计算，在对Acc进行计算的时候，也尽量避免Torch中的自有库，避免产生该类的问题/</p>
<h2 id="runtimeerror-the-derivative-for-target-is-not-implemented">RuntimeError the derivative for target is not implemented</h2>
<p>问题通常出现在损失计算的过程中，这个错误是由于我们在损失中的第二项 <code>targets</code>不应该有梯度，但是在这个地方却存在梯度导致的.</p>
<p>在这里我们可以通过仅仅取出 <code>tensor</code>的<code>data</code>或者使用<code>detach</code>and<code>copy</code>来进行数值的传递</p>
<h2 id="only-tensors-created-explicitly-by-the-user-graph-leaves-support-the-deepcopy-protocol-at-the-moment">Only Tensors created explicitly by the user (graph leaves) support the deepcopy protocol at the moment</h2>
<p>该错误是由deepcopy和require_grad, require_fn同时构成, 如果我们对一个需要计算梯度的非叶子节点进行deepcopy就会触发这个错误。</p>
<p>如果我们需要对这个数据进行存储的话，我们可以执行</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">save</span> <span class="o">=</span> <span class="n">copy</span><span class="o">.</span><span class="n">deepcopy</span><span class="p">(</span><span class="n">feature</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">cpu</span><span class="p">()</span><span class="o">.</span><span class="n">numpy</span><span class="p">())</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script>]]></content:encoded>
    </item>
    <item>
      <title>Loss-WhyZero</title>
      <link>https://aikenh.cn/posts/loss-whyzero/</link>
      <pubDate>Fri, 10 Dec 2021 08:24:46 +0000</pubDate>
      <guid>https://aikenh.cn/posts/loss-whyzero/</guid>
      <description>Do We Need Zero Training Loss After Achieving Zero Training Error</description>
      <content:encoded><![CDATA[<h1 id="loss-why-zero-loss">Loss :Why Zero Loss？</h1>
<p>@Comments: ICML2020 《Do We Need Zero Training Loss After Achieving Zero Training Error》</p>
<p>@Noteby：AikenHong2021</p>
<p>如何解决训练损失下降，但是验证损失上升的问题（过拟合like）的问题，该文章实际上可以作为我们损失设计中的一个trick，只需要简单的一行代码，来提升代码的泛化能力；</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211026211602.png">
    <img alt="img" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211026211602.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211026211602.png" style="display: block; margin: 0 auto;"
      alt="img"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>这张图体现了本文的灵魂（思路），主要体现在我们在算法趋于稳定后继续训练可能验证损失会反而上升；</p>
<p>所以本文提出了一种flooding方法，当我们training loss 大于阈值的时候我们使其正常下降，当低于阈值的时候，flooding的设计会反过来使得梯度上升，让训练损失保持在flooding附近，让模型持续进行random walk，希望模型最终能优化到一个平坦的损失区域，这样发现test loss进一步的进行下降。</p>
<p>理解：</p>
<p>当我们的训练损失低到一定的程度，然后随着lr的下降，模型会很难跳出当前的极小值，这种情况下我们的泛化能力也会被限制住，采用这种方法在牺牲测试精度的同时能提升算法的泛化能力。</p>
<p>损失公式表示如下</p>
<div>
$$ 
\widetilde{J}(\theta) = |J(\theta) - b| +b
 $$
</div>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211027104636.jpg">
    <img alt="v2-084a8f00d7349a94540fc7ad3a9433b0_r" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211027104636.jpg"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211027104636.jpg" style="display: block; margin: 0 auto;"
      alt="v2-084a8f00d7349a94540fc7ad3a9433b0_r"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>具体的代码表示只需要添加一层：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">b</span> <span class="o">=</span> <span class="n">the</span> <span class="n">flood</span> <span class="n">num</span> 
</span></span><span class="line"><span class="cl"><span class="n">new_loss</span> <span class="o">=</span> <span class="p">(</span><span class="n">loss</span> <span class="o">-</span> <span class="n">b</span><span class="p">)</span><span class="o">.</span><span class="n">abs</span><span class="p">()</span> <span class="o">+</span> <span class="n">b</span>
</span></span><span class="line"><span class="cl"><span class="n">optimizer</span><span class="o">.</span><span class="n">zero_grad</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">new_loss</span><span class="o">.</span><span class="n">backward</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">optimizer</span><span class="o">.</span><span class="n">step</span><span class="p">()</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>损失中怎么设置b值</strong></p>
<p>摘自知乎回答，我觉得这种方式说好也好，说不好也不好，算是一种治标不治本的trick把，通过这种方式可以勉强缓解那种代码陷入极小值无法调整的情况，但是实际上算法原理并不是一个很solid的</p>
<blockquote>
<p>看了下评论，不少人关心b值应该如何设置，首先论文给出说法是b做为超参数需要在一定范围内遍历选优，对于b得取值范围文中也仅有一个限定是：b值要小于测试损失，这个范围显然太宽泛了。也有人说应该在Validation Error 开始上升的时候，设置b值在此附近，进行flooding，因为此处说明已经开始过拟合，避免在错误方向上渐行渐远。个人觉得有道理，但是在自己的本地任务上尝试下来发现，通常来说b值需要设置成比&quot;Validation Error 开始上升&quot;的值更小，1/2处甚至更小，结果更优；想下来原因应该是：Validation Error开始上升的原因不仅仅使说明过拟合情况的发生，还有可能是验证机和训练集不满足独立同分布（这种情况更见），当原因是后者时，往往需要沿着梯度下降方向继续学习，也是解释通了实际使用种为何b值要设置的更小。</p>
</blockquote>
<p>和参数正则化之间的差异在哪里。</p>
]]></content:encoded>
    </item>
    <item>
      <title>Algorithm Sort</title>
      <link>https://aikenh.cn/posts/sorttrick/</link>
      <pubDate>Mon, 06 Dec 2021 17:05:03 +0000</pubDate>
      <guid>https://aikenh.cn/posts/sorttrick/</guid>
      <description>Implementation of Sorting Algorithm</description>
      <content:encoded><![CDATA[<p>记录各种排序操作，暂时不补充最基础的排序方式和理论，只记录排序算法的拓展应用。</p>
<p>在理论分析的部分主要使用cpp进行撰写，而在具体使用的时候，目前会主要按照python来进行编写，这主要是面向的场景不同决定的。</p>
<blockquote>
<p>基础的排序理论，包括快排等等算法的分析在另一篇文章中记录（当初实习准备的时候有整理过，后续重新整理出来）</p>
</blockquote>
<h2 id="排序算法和理论">排序算法和理论</h2>
<p>placeholder</p>
<h2 id="排序算法应用">排序算法应用</h2>
<p>placeholder</p>
<h3 id="同步排序">同步排序</h3>
<p>常用于Machine Learning中，将数据集中的数据和标签进行同步排序，避免打乱其中的对应关系。</p>
<p>使用numpy的 <code>argsort</code>功能来进行排序：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">idx</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">argsort</span><span class="p">(</span><span class="n">labels</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">labels</span> <span class="o">=</span> <span class="n">labels</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">datas</span> <span class="o">=</span> <span class="n">datas</span><span class="p">[</span><span class="n">idx</span><span class="p">,</span><span class="o">...</span><span class="p">]</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>使用<code>sort</code>中的<code>args: key</code>来进行同步排序，选出一个作为依据, 但是这种方式不支持存在np的情况，因为np无法建立hash，除非我们转化成tuple再转回来。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 默认按照第0维度进行排序</span>
</span></span><span class="line"><span class="cl"><span class="n">lables</span><span class="p">,</span> <span class="n">datas</span> <span class="o">=</span> <span class="p">[</span><span class="nb">list</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="o">*</span><span class="nb">sorted</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">labels</span><span class="p">,</span> <span class="n">datas</span><span class="p">)))]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 若要指定特定维度</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">operator</span> <span class="kn">import</span> <span class="n">itemgetter</span>
</span></span><span class="line"><span class="cl"><span class="n">datas</span><span class="p">,</span> <span class="n">labels</span> <span class="o">=</span> <span class="p">[</span><span class="nb">list</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="o">*</span><span class="nb">sorted</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">datas</span><span class="p">,</span> <span class="n">labels</span><span class="p">),</span> <span class="n">key</span><span class="o">=</span><span class="n">itemgetter</span><span class="p">(</span><span class="mi">1</span><span class="p">)))]</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>额外介绍<strong>我的愚蠢</strong>实现思路：</p>
<ul>
<li>用 $index/length$  作为小数位添加到 $labelList$ 上</li>
<li>$SORT$ 排序列表，分离并复原Index</li>
<li>基于Index对列表进行排序赋值</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">sort_dataset</span><span class="p">(</span><span class="n">dataset</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># the num_new_class can be calculate by some formula, but in this part make it HARD</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># sort those data and label which make it easier to del class.</span>
</span></span><span class="line"><span class="cl">    <span class="n">num_data</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">dataset</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">up_limit</span> <span class="o">=</span> <span class="nb">pow</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">num_data</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">    <span class="n">index</span> <span class="o">=</span> <span class="p">[</span><span class="n">index</span> <span class="o">/</span><span class="n">up_limit</span> <span class="k">for</span> <span class="n">index</span> <span class="ow">in</span> <span class="n">num_data</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1"># using this mark to sort the data</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">dataset</span><span class="o">.</span><span class="n">targets</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">dataset</span><span class="o">.</span><span class="n">targets</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+=</span> <span class="n">index</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">dataset</span><span class="o">.</span><span class="n">targets</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1"># get the new order </span>
</span></span><span class="line"><span class="cl">    <span class="n">new_order</span> <span class="o">=</span> <span class="p">[</span><span class="n">target</span> <span class="o">-</span> <span class="nb">int</span><span class="p">(</span><span class="n">target</span><span class="p">)</span> <span class="k">for</span> <span class="n">target</span> <span class="ow">in</span> <span class="n">dataset</span><span class="o">.</span><span class="n">targets</span><span class="p">]</span> <span class="o">*</span> <span class="n">up_limit</span>
</span></span><span class="line"><span class="cl">    <span class="n">dataset</span><span class="o">.</span><span class="n">targets</span> <span class="o">=</span> <span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="n">target</span><span class="p">)</span> <span class="k">for</span> <span class="n">target</span> <span class="ow">in</span> <span class="n">dataset</span><span class="o">.</span><span class="n">targets</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># it&#39;s necessary for us to swith to list or not?</span>
</span></span><span class="line"><span class="cl">    <span class="n">dataset</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">dataset</span><span class="o">.</span><span class="n">data</span><span class="p">)[</span><span class="n">new_order</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="kc">None</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script>]]></content:encoded>
    </item>
    <item>
      <title>UniFramework 01</title>
      <link>https://aikenh.cn/posts/uniframework/</link>
      <pubDate>Sat, 04 Dec 2021 01:43:30 +0000</pubDate>
      <guid>https://aikenh.cn/posts/uniframework/</guid>
      <description>The Design of the UniFramework 1</description>
      <content:encoded><![CDATA[<head>
    
    <script src="https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/crypto-js/3.1.9-1/crypto-js.js"></script>
</head>





<div class="hugo-encryptor-container">
  <div class="hugo-encryptor-prompt">
    
      <p>文章的部分内容被密码保护：</p>
    
  </div>
  <div class="hugo-encryptor-form">
    <input
      class="hugo-encryptor-input"
      placeholder='请输入密码'
    />
    <input
      class="hugo-encryptor-button"
      type="button"
      value='CLICK'
      onclick="_click_handler(this)"
    />
  </div>
  <div
    class="hugo-encryptor-cipher-text"
    data-password="aikenhong_blog"
    style="display: none;"
  >
    <span style="display: none;">--- DON'T MODIFY THIS LINE ---</span>
    <p>@aiken 2021  Framework</p>
<h2 id="abstract">Abstract</h2>
<p>Try To make structure universal，编写一个自己的通用的架构，框架化，满足通过不同的model文件和特殊配置文件就能实现不同的模型的一个架构。</p>
<p>只是一个初步的框架集成，还有很多没有完善的地方，目前测试了ResNet18 跑Cifar10，没有什么问题，如果有什么可以改进的地方，或者你实现了一些Feature，<em><strong>*欢迎进行交流*</strong></em>！（私下联系我最好啦！）</p>
<p>感谢帮助</p>
<ol>
<li>
<p>还有一些可以参数化或者可视化的地方，由于时间关系目前还没有修改，有兴趣的可以自己先添加一下</p>
</li>
<li>
<p>暂时只集成了分类的模块，后续可能会随缘扩展</p>
</li>
</ol>
<p>本框架主要希望实现的是：易读性，可拓展性，以及简洁；</p>
<p>希望将重要的，可变的参数都尽量的分离出来，通过配置文件和命令行参数去定义和运行我们的网络，在这种情况下实现一个较好的工作流程。</p>
<h2 id="final-project-design">Final Project Design</h2>
<p><strong>PURPOSE：新类发现和模型自主更新</strong>；同时希望能够解决<strong>长尾分布</strong>的数据情景；</p>
<p>**ANALYSIS：**为了实现这种模型的自主更新过程，将整体的流程分成两个部分</p>
<ul>
<li>
<p>启动（start）：</p>
<p>self supervissed 等方法无监督的学习特征提取网络（这种方式是否会对Unbalance产生增益）</p>
</li>
<li>
<p><strong>初始化预测模型：</strong>
基于<strong>Unbalance</strong>的数据训练一个基础的分类模型，在输出分类结果的同时需要输出对应的预测<strong>置信度</strong>，这两个其实都是一些简单的Trick，而最重要的是Backbone的分类效果需要得到保证，同时<strong>Backbone需要支撑后续的模型蒸馏</strong>更新。</p>
</li>
</ul>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210921164616.png">
    <img alt="image-20210921164615348" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210921164616.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210921164616.png" style="display: block; margin: 0 auto;"
      alt="image-20210921164615348"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ul>
<li><strong>模型的自主更新和迭代：</strong>
Online：在线运行推断模型，通过<strong>置信度输出筛选</strong>出新类样本，将样本在<strong>样本池</strong>中收集
Offline：基于样本池的规模和评估触发离线更新：<strong>伪标签生成模型</strong>；<strong>模型蒸馏和更新</strong></li>
</ul>
<p>创新点：自主新类发现和学习</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210921165300.png">
    <img alt="image-20210921165259383" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210921165300.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210921165300.png" style="display: block; margin: 0 auto;"
      alt="image-20210921165259383"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><strong>Unbalance：</strong></p>
<table>
  <thead>
      <tr>
          <th>Strategy</th>
          <th>Status</th>
          <th>Desc</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>Two Stage</strong></td>
          <td>Todo</td>
          <td>可以作为一个Baseline策略</td>
      </tr>
      <tr>
          <td><strong>Causla Analysis</strong></td>
          <td>Doing</td>
          <td>基于TwoStage做出的偏差校正</td>
      </tr>
      <tr>
          <td><strong>Rebalance</strong></td>
          <td>TBD</td>
          <td>作为数据增强的辅助策略</td>
      </tr>
  </tbody>
</table>
<p><strong>置信度生成方法：</strong></p>
<p>置信度生成的方法可以从<strong>Active Learning</strong>等领域的文章中作为参考</p>
<table>
  <thead>
      <tr>
          <th>Strategy</th>
          <th>Status</th>
          <th>pros and cons</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>Evidential Learning</strong></td>
          <td>Doing</td>
          <td>pros：有坚实的数学基础；<br />cons：增加模型复杂度和训练的难度</td>
      </tr>
      <tr>
          <td><strong>Least Confident</strong></td>
          <td>Done</td>
          <td>pros：实现简单，不影响原有复杂度<br />cons：原理上简单，不是特别靠谱</td>
      </tr>
      <tr>
          <td><strong>Entropy and&hellip;</strong></td>
          <td>TBD<br /></td>
          <td>同上，可以随时取代测试</td>
      </tr>
  </tbody>
</table>
<p><strong>置信度准确率评估：</strong></p>
<p>使用下面的指标去做置信度输出的准确率评估</p>
<div>
$$ 
ac = NumNew/NumLowconfi
 $$
</div>
<div>
$$ 
recall = NumOld/NumLowconfi
 $$
</div>
<p><strong>伪标签生成模型：</strong></p>
<p>在进行新的模型训练，之前，要将数据集混合现有的已知数据，生成的方式主要可以分成两种，<strong>网络</strong>或者<strong>聚类</strong></p>
<ul>
<li>聚类：通过现有类别的聚类结果，还能判断聚类的质量</li>
<li>网络：切分Mini-Batch进行Meta-Like的Training，训练FSL或者Unsupervised的模型，输出伪标签预测（一致性原则）</li>
</ul>
<p>基本思想：</p>
<ol>
<li>当特征以通用表征的无监督预训练进行，这种情况下不存在对应的数据瓶颈，因为我们不需要标记，我们可以将Backbone得到一个泛化性极强的高级特征，那么在这种情况下LT和FC带来的泛化性问题将集中在Classifier中，对Classifer进行校准和调整就是我们的主要方向，这样就能将问题归化到蒸馏和FC的训练一个Linear的问题</li>
<li>所以处理Unbalance的分类器和特征迁移方式是我们后续work的方向，可以从复杂度高的网络训练一个高级表征的分类器，或者通过Graph和Cluster的构建，来实现一个更为依赖Backbone的一种方式。</li>
</ol>
<p>创新点：</p>
<ul>
<li>（Augmentation）在做伪标签生成之前，我们基于原本特征特征提取器，组合数据特征，数据混合和增强方法作为后续的数据基础</li>
<li>（Loss-Design）通过混合的数据集中的伪标签生成，和标签的双指标，定义损失，去更新原有的特征提取架构同时赋予新类伪标签。这是由于我们知道部分数据集的真实标签，我们就可以通过这一部分的信息去做一个对应的标准。</li>
<li>这样就可以通过生成的伪标签对原特征提取器进行一定的更新，这种更新应该是交替进行的，因为我们不知道哪个Coder是更为可靠的一个label generator。（除非我们使用的是有终点的聚类）</li>
</ul>
<p><strong>模型更新：</strong></p>
<p>参考蒸馏学习的思想，使用原有网络和pseudo generator作为Teacher 进行模型的更新，Duplicate Feature Extractor，Modify FC（num_class），考虑使用双重循环去freeze，利用不同的lr training网络的两部分。</p>
<ul>
<li>
<p>在这里参考其他蒸馏学习的方法，去设计这种Teacher给予Label或者Parms的机制</p>
</li>
<li>
<p>考虑基于prototype的方法，是否会和聚类的方法更加的匹配，但是prototype</p>
<p>的方法和我们之前设想的实验过程应该是一个区分度比较大的情况</p>
</li>
</ul>
<p>创新点：</p>
<ul>
<li>（Framework）double teacher to generate a new siamese model which train in two diff phase for feature extractor and classifier
使用孪生的机制，在两个不同的阶段来训练特征提取器和分类器，在这里我们将训练的重心转化到Projector以及Cluster，Model上</li>
</ul>
<p><strong>设计思路</strong></p>
<p>在模型的整体架构上还是会和awb师弟的有很多类似的地方，后续可以详细进行探讨和借鉴。</p>
<h2 id="devlog">DevLog</h2>
<p>开发中的一些疑问和细节会放在这个地方，包括开发的RoadMap，实现中遇到的问题，FrameWork设计中的主要矛盾和问题。</p>
<p>下面是一些基本的实验内容：首先将流程跑通，在设计对应的消融实验。</p>
<h3 id="full-data-的模型基准实验">Full-Data 的模型基准实验</h3>
<table>
  <thead>
      <tr>
          <th>BackBone测试</th>
          <th>数据集</th>
          <th>进度</th>
          <th>结果</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>resnet-18</td>
          <td>cifar10</td>
          <td>完成（配置文件已保存）</td>
          <td>93%</td>
      </tr>
      <tr>
          <td></td>
          <td>cifar100</td>
          <td>完成（配置文件已保存）</td>
          <td>77%</td>
      </tr>
      <tr>
          <td></td>
          <td>ImageNet</td>
          <td></td>
          <td></td>
      </tr>
      <tr>
          <td>conclusion</td>
          <td></td>
          <td>过拟合in cifar100</td>
          <td></td>
      </tr>
      <tr>
          <td>Efficient Net b0</td>
          <td>cifar10</td>
          <td>完成（非最佳）（配置文件已保存）</td>
          <td>90%</td>
      </tr>
      <tr>
          <td></td>
          <td>cifar100</td>
          <td>完成（非最佳）（配置文件已保存）</td>
          <td>73%</td>
      </tr>
      <tr>
          <td></td>
          <td>ImageNet</td>
          <td></td>
          <td></td>
      </tr>
      <tr>
          <td>conclusion</td>
          <td></td>
          <td>过拟合in cifar</td>
          <td></td>
      </tr>
      <tr>
          <td>Swin Transformer</td>
          <td></td>
          <td></td>
          <td></td>
      </tr>
      <tr>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
      </tr>
  </tbody>
</table>
<p>实际上在训练集和测试集中，resnet18 和 efficient net呈现的都是一种训练集远高于数据集的过拟合like的情况，我认为这种情况与问题规模简单，等诸多原因导致，为了改善这种情况，我们可以考虑</p>
<ol>
<li>使用更多数据增强来使得问题更为复杂</li>
<li>使用特征学习无监督与训练的方法，同样通过数据增强来加大问题规模</li>
<li>增加数据，使用大规模数据集对模型进行与训练，但是也要考虑到数据的规模和模型的capability</li>
</ol>
<h3 id="cifar10-100的模型调优过程">Cifar10-100的模型调优过程</h3>
<p>后续可以考虑加入MAE的方式，实际上这种方式就是代替了EnAET中的多种复杂数据增强，还是从数据增强的角度入手对模型进行处理实现的一种自监督的机制，这种自监督的策略来学习一种图像上的通用表征，保持在识别问题上，整体的有效性。</p>
<h4 id="resnet">ResNet</h4>
<p>在对cifar10-100的图像进行分类的时候需要修改初始的入口层，因为cifar数据集中的图像太小，如果一开始使用7*7的卷积层，在精度上会损失很多特征信息。</p>
<ul>
<li>可以将7*7 2的卷积改成3*3 1,然后去掉maxpooling层</li>
<li>亦可以将图像resize到224*224</li>
</ul>
<p>前者在cifar10中最终测试可得接近93%的准确率，在cifar100中最终测试可以取得稳定77%的准确率</p>
<p>此外，对图像进行<code>randomcrop</code>的过程中，由于原图本来就只有<code>32*32</code>所以我们希望crop到32的时候，我们最好是先进行padding，不然该增强是一个无效的增强。</p>
<h4 id="efficient-net">Efficient Net</h4>
<p>和对ResNet进行调整的时候一样，训练集太过简单，所以过快的收敛，影响了模型的泛化能力，这里考虑可能是dropout没有设置好，或者是任务过于简单，我们可以对其设置一些图像的增强等等的操作来对对训练过程进行调整，可以将一部分需要较多io的任务存放在本地，然后在线进行一些random transformer。</p>
<p>在这里不需要对模型进行修改，只需要调整学习的参数即可。</p>
<h4 id="swin-transformer">Swin Transformer</h4>
<hr>
<h3 id="在new-class---lt-的数据环境中的基准实验">在new class - LT 的数据环境中的基准实验：</h3>
<p>首先测试LT和NC的数据策略是否能进行正常的数据训练，确保数据抽取策略</p>
<p>后续为了可复现和效果对比，我们在<strong>类别抽取的时候取消随机性</strong>（使用固定的随机种子），抽取固定的类别作为新类，对比未进行长尾采样以及采样之后的效果。</p>
<table>
  <thead>
      <tr>
          <th>model</th>
          <th>数据集以及预处理</th>
          <th>进度</th>
          <th>LT结果</th>
          <th>NC结果</th>
          <th>Combine</th>
          <th>TAG</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>&hellip;</td>
          <td>cifar10， cifar100<br />分别测试LT和NC的策略</td>
          <td>Done</td>
          <td>:heavy_check_mark:</td>
          <td>:heavy_check_mark:</td>
          <td>\</td>
          <td>varify</td>
      </tr>
      <tr>
          <td>resnet</td>
          <td>cifar100 NC：20 LT：0.5(step)</td>
          <td>Done</td>
          <td>\</td>
          <td>75%-.5</td>
          <td>\</td>
          <td>try</td>
      </tr>
      <tr>
          <td></td>
          <td>pre-cifar100 NC20 LT0.5(STEP)</td>
          <td>Done</td>
          <td>63%</td>
          <td>75%-.5</td>
          <td>63%- 0.5</td>
          <td>basic</td>
      </tr>
      <tr>
          <td>下面开始矫正</td>
          <td>问题更大的实际上是LT部分</td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
      </tr>
      <tr>
          <td>resnet-CA</td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
      </tr>
      <tr>
          <td>resnet-ReBalance</td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
      </tr>
      <tr>
          <td>resnet-MAR-iBOT</td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
      </tr>
      <tr>
          <td>Efficient Net</td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
      </tr>
      <tr>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
      </tr>
      <tr>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
      </tr>
      <tr>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
      </tr>
      <tr>
          <td>Swin Transformer</td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
      </tr>
      <tr>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
      </tr>
  </tbody>
</table>
<h4 id="实验结果一置信度问题">实验结果一：置信度问题</h4>
<p>使用Cifar100置信度划分的过程中，发现对新类的筛选效果并不好，我们考虑，这可能是由于超类和子类之间的关系造成的，为此，在初步的研究阶段，我们决定，<strong>拆分出特定的超类来作为新类</strong>，避免对于新类识别的干扰；</p>
<ul>
<li>后续的研究中可以考虑像安文斌的方式去做<strong>纵向的新类发现</strong>，现阶段首先考虑<strong>横向的新类发现问题</strong>，在这里可以参考<strong>安文斌师弟的两个研究</strong></li>
</ul>
<blockquote>
<ol>
<li>
<p>实际上新类的拆分要求的是<strong>precision</strong>，相对的<strong>recall</strong>在当前的问题上并不是很重要，所以对该算法的改进不是很迫切，但是相应的，我们需要完善recall和Precision的输出用来作为我们后续进行判断的依据</p>
</li>
<li>
<p>拆分特定新类的情况下，置信度结果并没有明显的改进，说明问题更多的出自模型的特征提取和分类本身，用于分类的特征没有将类别之间的差异性体现出来，所以后续在这一方面的训练应该进行改进，改进思路如下：</p>
</li>
</ol>
</blockquote>
<p>修改Loss：使用Contrastive Learning的训练策略，在分类准确率之上结合NLL对比损失，在这一部分可以结合人脸比对的相应损失进行设计</p>
<p>实际上我们可以用MAE训练一个通用的预训练表征，Backbone，然后使用Contrastive训练Classifier，两种不同的策略的侧重点实际上是不一样的。那么如何结合这两种训练方式，或者将其中的一种训练和分类的训练相互结合起来，使得我们的训练步骤不会如此的冗余。</p>
<blockquote>
<p>Contrastive Learn的预训练方式：得到一个类别之间更为分明的Backbone or MLP？</p>
<p>MAE的预训练方式，得到一个通用的表征？</p>
</blockquote>
<h4 id="实验结果二lt问题">实验结果二：LT问题</h4>
<p>准确率下降到63%（下降了10%左右），过拟合问题愈发严重，需要更多的去分析这种下降出现的原因。</p>
<h3 id="distill部分网络结构设计">Distill部分网络结构设计</h3>
<p>为了使得能够进行代码复用，不做重复的造轮子，在对蒸馏部分网络进行设计的时候遇到了一些问题，以下是问题和解决方式，假如这些方式不能很好的解决对应的问题，我们就duplicate代码并重新编写Train_ditill 的设计</p>
<p>这一部分其实设计的是整个框架中的数据流程，要注意在每个不同的阶段我们使用的数据是不同的。如何更有效的利用这个数据，是框架设计中的关键部分。</p>
<h4 id="损失部分对输入的要求不同">损失部分对输入的要求不同</h4>
<p>面临<strong>问题</strong>：</p>
<ol>
<li>需要额外的模型输出作为Loss的计算依据</li>
<li>损失函数的输入维度不统一</li>
</ol>
<p>暂定<strong>解决方案</strong>，</p>
<ul>
<li>（Both）使用额外的args参数对损失计算的部分进行分支处理</li>
</ul>
<h4 id="伪标签的处理">伪标签的处理</h4>
<p>具体<strong>问题</strong>：</p>
<ol>
<li>在什么阶段将标签转化为对应的伪标签</li>
<li>如何和真实标签进行一个对照分析，如何保存并实现验证和真实环境的匹配度</li>
</ol>
<p>暂定<strong>解决方案</strong>：</p>
<p>再labelGe中仿照人类标注，按照绝大多数类别的真是标签来确定伪标签，然后再初始化蒸馏训练中，将训练集中的数据替换为伪标签，而test数据集中仍然是真实标签，就解决了验证的问题和伪标签和真实标签之前缺乏一次映射的问题。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/dbf13e29e9692b46da06f1dfde735e2.jpg">
    <img alt="align mcanism" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/dbf13e29e9692b46da06f1dfde735e2.jpg"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/dbf13e29e9692b46da06f1dfde735e2.jpg" style="display: block; margin: 0 auto;"
      alt="align mcanism"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="roadmap">RoadMap</h3>
<p>开发路线图部分，主要分为基本的模块，和不同的训练方式两个阶段，用来集成完整的Framework.</p>
<h4 id="deadline-settting">Deadline Settting</h4>
<p>具体时间节点，主要是为了给自己明确当前的任务，后续可能会继续细化，时间上也会随着实验的顺利与否进行调整。</p>
<table>
  <thead>
      <tr>
          <th>Task</th>
          <th>Desc</th>
          <th></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>部分功能重写</td>
          <td>config，dataloader（read data and load in GPU）<br />by define collate_fn function</td>
          <td>完成</td>
      </tr>
      <tr>
          <td>数据处理</td>
          <td>几个部分的数据还有整体的数据：New（FS divide into phase？）-Old（LT）-Cloud（无关数据）</td>
          <td>完成</td>
      </tr>
      <tr>
          <td>调整运行Swin</td>
          <td>交织在多个任务中并行，时不时的调整参数测试一下</td>
          <td>待定</td>
      </tr>
      <tr>
          <td>长尾模块功能实现</td>
          <td>在cifar数据集上用resnet先进行实验和swin的实验并行<br />实现对长尾的优化</td>
          <td>进行</td>
      </tr>
      <tr>
          <td>小样本模型和聚类模型嵌入</td>
          <td>1. 确定数据混合策略<br />2. EnAet中训练的策略集成到该函数中<br />3 确定标签的输出和参与的形式</td>
          <td>进行</td>
      </tr>
      <tr>
          <td>蒸馏架构实现</td>
          <td>架构编写，实现蒸馏框架的嵌入<br />测试双模型之间的蒸馏的结果</td>
          <td>完成</td>
      </tr>
      <tr>
          <td>模型实验和测试</td>
          <td></td>
          <td></td>
      </tr>
  </tbody>
</table>
<h4 id="data">Data</h4>
<p>数据集收集和初始数据的采样处理：</p>
<p>分析一下数据的使用场景：</p>
<p>首先我们使用Unbalance的数据进行初始模型的构建，然后我们需要在训练的过程中加入小样本的新类别。</p>
<p><em>可以额外的构建小样本的数据集来训练小样本模型，但这不在我们的Workflow里，不作为我们的主题框架中的代码。</em></p>
<table>
  <thead>
      <tr>
          <th>Function</th>
          <th>Stage</th>
          <th>Desc</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>New Class（Larget version）</td>
          <td><strong>done</strong></td>
          <td>like mini-imagenet，<code>mv</code> some cls to other dir</td>
      </tr>
      <tr>
          <td>Unbalance</td>
          <td><strong>done</strong></td>
          <td>sampling data in differ rate</td>
      </tr>
      <tr>
          <td>Mix data</td>
          <td><strong>done</strong></td>
          <td>mix old knowledge and the new data，the point:<br />whether we want to use meta-learning or pnot</td>
      </tr>
      <tr>
          <td>Few Shot</td>
          <td><strong>done</strong></td>
          <td>testing the model only have few data</td>
      </tr>
  </tbody>
</table>
<p>所以数据准备工作应该分为两步：</p>
<p>（Script）数据集预处理，将一部分类别抽离出去，建立新的文件夹，但是对于Cifar这种数据集好像都是一次性载入的，思考一下怎么写成对应的函数进行处理。</p>
<p>（Load）初始数据的Unbalance处理，通过不同的采样策略使得数据不均衡</p>
<p>此外，我们在进行新类训练的时候会将旧数据和新数据进行混合，我们需要设计对应的数据混合策略，进行小样本模型的训练和聚类的训练</p>
<h4 id="model">Model</h4>
<table>
  <thead>
      <tr>
          <th>Functional Part</th>
          <th>Stage</th>
          <th>KeyWord/Method</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>Basic Training</strong></td>
          <td>abjust</td>
          <td>ImageNet1k Using ImageNet to Pretrain or Self-Training</td>
      </tr>
      <tr>
          <td><strong>Backbone</strong></td>
          <td>todo</td>
          <td>Swin（abjust params and train on ImageNet）<br /></td>
      </tr>
      <tr>
          <td><strong>LT and Confidence</strong></td>
          <td>done</td>
          <td>two-stage<br />rebalance<br />causal analysis</td>
      </tr>
      <tr>
          <td><strong>FSL</strong></td>
          <td>doing</td>
          <td>Self-Supervise<br />Cluster</td>
      </tr>
      <tr>
          <td><strong>Cluster</strong></td>
          <td>todo</td>
          <td>New-Descover<br />K-Means<br />Self-Supervised + linear</td>
      </tr>
  </tbody>
</table>
<h4 id="framework">Framework</h4>
<table>
  <thead>
      <tr>
          <th>Training Process</th>
          <th>Stage</th>
          <th>KeyWord/Method</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>Meta Training</strong></td>
          <td>TBD</td>
          <td>/</td>
      </tr>
      <tr>
          <td><strong>Multi-Stage Training</strong></td>
          <td>Intergrate with Framwork</td>
          <td>/</td>
      </tr>
      <tr>
          <td><strong>Distill Training</strong></td>
          <td>done</td>
          <td>Incremental learning,</td>
      </tr>
      <tr>
          <td><strong>Unsupervised</strong></td>
          <td>todo</td>
          <td>MAE</td>
      </tr>
      <tr>
          <td><strong>Clustering</strong></td>
          <td>doing</td>
          <td>Projector-Head + Kmeans</td>
      </tr>
  </tbody>
</table>
<h3 id="swin-t">Swin-T</h3>
<p>问题描述：在cifar10，或者ImageNet数据集上训练的时候，损失曲线过早收敛，识别准确率很低；</p>
<p>问题分析：</p>
<ol>
<li>LR 过高，没有办法学到好的解</li>
</ol>
<p>框架中学习率设置的问题，同理可以分析其他的和config中的冲突</p>
<ol start="2">
<li>
<p>数据集标签的问题</p>
</li>
<li>
<p>模型定义的问题</p>
</li>
<li>
<p>损失函数设计，模型的体量问题</p>
</li>
</ol>
<p>解决方法拟定：</p>
<ul>
<li>直接使用官方的模型和官方的数据集进行训练后比对</li>
<li>加载并编写论文中提到的各种trick</li>
<li>对比官方的模型和自己编写的模型之间的差异</li>
</ul>
<h2 id="dataset">Dataset</h2>
<p>这一部分描写使用到的dataset的具体参数，主要至少包含一下的一些信息</p>
<table>
  <thead>
      <tr>
          <th>Name</th>
          <th>Class</th>
          <th>EachNum</th>
          <th>Resolution</th>
          <th>Useage</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Cifar10</td>
          <td>10</td>
          <td>5000+1000</td>
          <td>32*32</td>
          <td>Cls LT</td>
      </tr>
      <tr>
          <td>Cifar100</td>
          <td>100</td>
          <td>500+100</td>
          <td>32*32</td>
          <td>Cls NC LT</td>
      </tr>
      <tr>
          <td>TinyImageNet</td>
          <td>200</td>
          <td>500+50+50</td>
          <td>64*64</td>
          <td>Cls NC LT</td>
      </tr>
      <tr>
          <td>MiniImageNet</td>
          <td>100</td>
          <td>500+100</td>
          <td>86*86</td>
          <td>Cls NC LT</td>
      </tr>
      <tr>
          <td>ImageNet-1k</td>
          <td>1000</td>
          <td>700-1300</td>
          <td>resize to (256*256)<br />avg:469*387</td>
          <td>PreTrain</td>
      </tr>
  </tbody>
</table>
<p>If Need List the dataset here :</p>
<p><a href="https://github.com/rmccorm4/Tiny-Imagenet-200" target="_blank" rel="noopener">Tiny-ImageNet-200</a>
 | Tiny-ImageNet-<a href="https://www.cnblogs.com/liuyangcode/p/14689893.html" target="_blank" rel="noopener">Plus</a>
</p>
<h2 id="reference">Reference</h2>
<p><strong>Confidental</strong></p>
<p><a href="https://www.zhihu.com/question/265479171/answer/1474978784" target="_blank" rel="noopener"> 主动学习(Active learning)算法的原理</a>
</p>
<p><strong>ResNet</strong></p>
<p><a href="https://pytorch.org/vision/stable/_modules/torchvision/models/resnet.html#resnet18" target="_blank" rel="noopener">Pytorch.org</a>
、<a href="https://www.cnblogs.com/wzyuan/p/9880342.html" target="_blank" rel="noopener">官方实现解读</a>
 、<a href="https://www.cnblogs.com/shine-lee/p/12363488.html" target="_blank" rel="noopener">ResNet详解与分析</a>
、<a href="https://zhuanlan.zhihu.com/p/149387262" target="_blank" rel="noopener">Pytorch手工实现</a>
</p>
<p><strong>Mini ImageNet</strong></p>
<p><a href="https://blog.csdn.net/qq_37541097/article/details/113027489" target="_blank" rel="noopener">用Mini-ImageNet训练分类网络</a>
</p>
<p><strong>Swin Transformer</strong></p>

  </div>
</div>

<script>
    


function sanitizeContent(content) {
    
    return content.replace(/[\x00-\x1F\x7F]/g, '').trim(); 
}

function encryptContent(password, content) {
    const key = CryptoJS.MD5(password).toString();
    const iv = key.substring(16); 
    const paddedContent = padContent(content);
    const encrypted = CryptoJS.AES.encrypt(paddedContent, CryptoJS.enc.Utf8.parse(key), {
        iv: CryptoJS.enc.Utf8.parse(iv),
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
}

function padContent(content) {
    const blockSize = 32; 
    const padlen = blockSize - (content.length % blockSize);
    
    
    return content;
}

function processEncryptedBlocks() {
    const blocks = document.querySelectorAll('.hugo-encryptor-cipher-text');
    blocks.forEach(block => {
        const password = block.getAttribute('data-password');
        const content = block.innerHTML.trim(); 
        const sanitizedContent = sanitizeContent(content); 
        const encryptedContent = encryptContent(password, sanitizedContent);
        block.innerHTML = encryptedContent;
        block.removeAttribute('data-password');
    });

    
    const script = document.createElement('script');
    script.src = '/js/decrypt.js';
    document.body.appendChild(script);
}


document.addEventListener('DOMContentLoaded', processEncryptedBlocks);
</script>
]]></content:encoded>
    </item>
    <item>
      <title>Hungarian</title>
      <link>https://aikenh.cn/posts/hungarian/</link>
      <pubDate>Fri, 03 Dec 2021 00:29:37 +0000</pubDate>
      <guid>https://aikenh.cn/posts/hungarian/</guid>
      <description>Matching Algorithm</description>
      <content:encoded><![CDATA[<p>@AikenHong 2021
@Code: <strong>Scipy</strong>（repo）
@Reference:  <a href="https://zhuanlan.zhihu.com/p/62981901" target="_blank" rel="noopener">匈牙利算法&amp;KM算法</a>
</p>
<p>该篇笔记用来介绍匈牙利算法和KM算法(Kuhn-Munkres Algorithm)，这两个算法通常用来做目标之间的匹配问题。
常用于：多目标跟踪，和深度聚类中的标签匹配问题。</p>
<h2 id="method">Method</h2>
<p>这两种方法实际上解决的问题都是： 二分图的最大匹配问题；
首先需要对二分图有个基本的了解：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211202164156.png">
    <img alt="二分图" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211202164156.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/20211202164156.png" style="display: block; margin: 0 auto;"
      alt="二分图"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>实际上就是将数据分为两组，各组的每一个点都去另一个组找对应的匹配，我们希望将两组中，相关的数据尽可能的准确的匹配起来。</p>
<blockquote>
<p>可以想象成，是同一个数据在不同的映射下的不同表征需要做这样的匹配关系。</p>
</blockquote>
<p>解决这种问题的方式就是使用匈牙利算法或者KM算法</p>
<h3 id="匈牙利算法">匈牙利算法</h3>
<blockquote>
<p>匈牙利算法是一种在多项式时间内求解任务分配问题的组合优化算法</p>
</blockquote>
<p>匈牙利算法可以将二分图中的连线，看成是我们认为可能是相同的目标（不带权值），实际上就是从上到下假想成立，然后进行唯一匹配的搜索，有点像BackTrack的过程。</p>
<p>整体算法的成功率或者准确率实际上十分依赖与连线的准确率，对算法输出预测的准确度要求更高。</p>
<h3 id="km">KM</h3>
<blockquote>
<p>KM解决的是带权的二分图的最优匹配的问题。</p>
</blockquote>
<p>相当于我们给每条线都给出一个置信度预测值，基于这样的权值图去计算对应的匹配关系</p>
<p>Step1: 将左边节点标上与他所关联的最大权值的边的数值
Step2: 寻找匹配，原则如下</p>
<ul>
<li>只有权重和左边分数相同的边才进行匹配；</li>
<li>如果找不到边，此条路径的所有左边顶点-d，右侧+d，这里我们将d取值为0.1</li>
<li>对于考虑换边的另一个节点，如果无法换边，也需要对应的进行-d</li>
</ul>
<p>具体的例子可以这么看（最好还是看blog）：

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/cf20ef3a1fa97ecf3dc0e4c620f61b8.jpg">
    <img loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/cf20ef3a1fa97ecf3dc0e4c620f61b8.jpg"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/cf20ef3a1fa97ecf3dc0e4c620f61b8.jpg" style="display: block; margin: 0 auto;"
      alt=""  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="code">Code</h2>
<p>使用scipy中的集成版本实现，但是要注意对应的输入是二分图的cost_matrix</p>
<p>算法的实现应该是将最大的权值转换成了最大代价来进行计算的，所以为了使用KM算法，我们首先应该构造对应的损失矩阵。</p>
<p>假如我们使用相似度指标计算的话，对应的大小关系应该做一个反转，可以直接用负号进行计算，计算完相似度直接取一个负值进行计算。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">scipy.optimize</span> <span class="kn">import</span> <span class="n">linear_sum_assignment</span>
</span></span><span class="line"><span class="cl"><span class="n">row_ind</span><span class="p">,</span> <span class="n">ol_ind</span> <span class="o">=</span> <span class="n">linear_sum_assignment</span><span class="p">(</span><span class="n">cost_matrix</span><span class="p">,</span> <span class="n">maximize</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/dbf13e29e9692b46da06f1dfde735e2.jpg">
    <img alt="Build Your Cost Matrix" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/dbf13e29e9692b46da06f1dfde735e2.jpg"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/labimg/dbf13e29e9692b46da06f1dfde735e2.jpg" style="display: block; margin: 0 auto;"
      alt="Build Your Cost Matrix"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
]]></content:encoded>
    </item>
    <item>
      <title>Cherno的cpp教程笔记</title>
      <link>https://aikenh.cn/posts/cpp/</link>
      <pubDate>Mon, 29 Nov 2021 13:12:17 +0000</pubDate>
      <guid>https://aikenh.cn/posts/cpp/</guid>
      <description>cherno(ytb)-cpp-lesson</description>
      <content:encoded><![CDATA[<p>this notebook is based on Cherno‘s Video Class in <a href="https://www.youtube.com/watch?v=wXBcwHwIt_I&amp;list=PLlrATfBNZ98dudnM48yfGUldqGD0S4FFb&amp;index=62&amp;ab_channel=TheCherno" target="_blank" rel="noopener">YouTube</a>
；if there is sth get confused，I can <strong>recheck</strong> the video which talk about it, or <strong>just google it</strong>.</p>
<ul>
<li>this is not totally for newbie, so some basic information we should search it</li>
<li>And this is a important <a href="https://zh.cppreference.com/w/%E9%A6%96%E9%A1%B5" target="_blank" rel="noopener">websize</a>
 to tell us basic info about C++.</li>
</ul>
<p><strong>ToDo:</strong></p>
<ul>
<li><input checked="" disabled="" type="checkbox"> using c++ and Python to finish the leetcode.</li>
<li><input checked="" disabled="" type="checkbox"> review data structure when we code.</li>
<li><input disabled="" type="checkbox"> eorganize the notebook by onenote** and leetcode</li>
<li><input disabled="" type="checkbox"> 后续可能会添加 Effetive C++中的相关内容</li>
<li><input disabled="" type="checkbox"> C++ Switch<a href="https://www.runoob.com/cplusplus/cpp-switch.html" target="_blank" rel="noopener">语句</a>
</li>
</ul>
<p><strong>Attention：</strong></p>
<ul>
<li>为了防止一些遗漏，或者搜索上的困难，虽然我们会尽量避免内容的overlap，但是如果和两者都特别相关的话，可能会在两个地方出现完全一致的内容。</li>
<li><strong>后续补充</strong>：如果是confused的内容（不确信的话）就加入:question:  或者 still in puzzle: 内容的格式添加把</li>
<li><a href="https://support.typora.io/Shortcut-Keys/#change-shortcut-keys" target="_blank" rel="noopener">Typora常用快捷键</a>
</li>
</ul>
<h2 id="introduction-about-c">Introduction About C++</h2>
<p>C++是一种强类型的语言，也就是我们需要实现指定数据的类型，同时我们没法随意的改变类型或者混杂类型把。（其实也是可以的就是需要执行特定的代码，相对而言没有那么方便而已。）</p>
<p>有疑惑就去查cppreference，永远的神；此外当我们对某个不知道什么时候用的时候就google xxx when why how.</p>
<h2 id="part-1-编译器基本工作原理">Part 1 编译器基本工作原理</h2>
<p>Visual Studio中C++的<strong>compiler，linker</strong>的基本工作原理；以及在Visual Studio中一些相关工作环境的设置，比如<strong>输入输出配置</strong>，<strong>debugging</strong>环境之类的；此外建议使用VsCode的<strong>键盘映射</strong>，对于自己来说比较熟悉）；同时也会介绍一些和编译器原理相关的<strong>预处理模块</strong>；以及<strong>Library</strong></p>
<h3 id="基本信息">基本信息</h3>
<p>STD：standard library C++中的标准库，包含了一些最基础的标准操作，包括<code>cin; cout;``&lt;cmath&gt;</code>
#:hash tag（预处理符号）+预处理语句（基本的就是include，define之类的） = 预处理器</p>
<h3 id="build-compiler--linker的基本原理">Build ：Compiler + linker的基本原理</h3>
<p><strong>编译和连接的规则：</strong></p>
<p><strong>原则1：</strong>.Cpp都会被编译，但是.h不会被编译，他是以#后接的指定模式(<code>include</code>被嵌入(copy)到指定的.Cpp中的指定位置再进行编译。（下面是一些预处理指令）</p>
<blockquote>
<ol>
<li>
<p><code>include</code>：直接<strong>复制粘贴</strong>到**指定的位置，**所以你也可以定义}之类的进入h。</p>
</li>
<li>
<p><code>define</code>：搜索并<strong>替换</strong></p>
<p>可以用做简单的函数定义</p>
<p>也可以使用成定义pi的值之类的，指定一个名称</p>
</li>
<li>
<p><code>#if 0/1 … #endif</code>:中间的内容将根据if后的true or false 来决定是否存在。（是否编译）</p>
</li>
</ol>
</blockquote>
<p>上述的三种操作都是<strong>文本级别</strong>的操作，也就是针对编码文本进行处理后再送入编译器进行编译的。</p>
<p>**原则2：**每个cpp都会被编译成.obj文件然后由Linker，将这些obj连接起来成为一个.exe</p>
<ul>
<li>
<p><strong>THIS IS IMPORTANT：<strong>如果我们想要将功能和主体main（entrypoint）分离开来，除了用header的方式，我们也可以写在另外的.cpp中，然后再主要文件中进行declaration（定义函数名和指定的传入参数即可），也就是</strong>声明该函数是存在的</strong>，而不用具体定义（具体定义在另外的cpp中），这样在build的过程中，linker就会在我们的工程项目文件夹中搜索其他cpp中的指定function（we just declaration in the main cpp）。这样也能成功的编译。</p>
</li>
<li>
<p>所以如果我们一个函数在多个cpp中定义（多重定义），或者由于header中的include h，这样可能会导致compile的时候出现代码（链接？）<strong>混淆</strong>的问题（bug），再不济也是个冗余的编译操作。</p>
<ul>
<li>
<p>如果需要多次使用.h文件，我们可以将其中的函数定义成<strong>static</strong>的方式，这样在每个cpp中都会有自己版本的.h中的函数，就不会有重复编写导致模棱两可的问题了。</p>
</li>
<li>
<p>inline前缀也能解决同样的问题：内联函数</p>
<blockquote>
<p><strong>inline：内联标识符</strong>适用于结构简单的小型函数。</p>
<p>增加了 inline 关键字的函数称为“内联函数”。内联函数和普通函数的区别在于：当编译器处理调用内联函数的语句时，不会将该语句编译成函数调用的指令，而是直接将整个函数体的代码插人调用语句处，就像整个函数体在调用处被重写了一遍一样。</p>
</blockquote>
</li>
</ul>
</li>
<li>
<p>所以在这里我们推荐<strong>在header中只实现Declaration</strong>，而具体<strong>的Definition就只在某一个cpp中</strong>进行编写。</p>
</li>
</ul>
<p>**机器码：**Visual Studio中可以将输出的obj之类的，包括代码中转化成汇编代码去看，就能知道我器的实际运行逻辑，在VisualStudio中我们也可以设置针对汇编的自动优化来提升算法的运行速度。（一般是在release中会自动优化，而Debug中便于定位问题就没有优化）</p>
<p><strong>Debug标识符</strong>： C：Compile Error；LINK：Linker Error</p>
<p><strong>Static标识符</strong>：在变量的部分细讲，实际上对于编译过程也是一个很重要的关键词</p>
<h3 id="build-头文件header-files">Build： 头文件（Header Files）</h3>
<p><strong>一般在header 中写入declaration，然后把definition写在Cpp files里面。</strong></p>
<p><strong>#Include 命令</strong> &quot;&quot; 或 &lt;&gt;</p>
<ul>
<li>&ldquo;[content]&rdquo; : content是文件的相对路径，可以使用类似..去索引</li>
<li>&lt;&gt;:一般用来索引标准库之类的，用&quot;&ldquo;来存储.h之类的文件</li>
<li>有.h后缀的导入一般是C，Cpp的就没有后缀</li>
</ul>
<p><strong>#Pragma once</strong>
这个hash tag的作用是让预处理仅仅只编译头文件一次，就是多次import也不会重复编译把，这个东西不要删除它。</p>
<p>原理上是取代了原本的ifnder；实际上也是一个宏</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="cp">#ifndef Tag1_H
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="kt">void</span> <span class="nf">functionA</span><span class="p">(</span><span class="kt">int</span> <span class="n">var1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="cp">#endif</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>**基本概念：**使用通用的header文件，将一些include放入header中，然后对这些header进行预编译，生成二进制文件。这样的话，</p>
<blockquote>
<ul>
<li>我们就不需要每个cpp中的#include .h 都对其中的所有的include在进行copy paste然后进行编译，这样的话，加入了很多不必要的编译过程。</li>
<li>也不用每次修改代码进行编译测试的时候，都有繁重的编译工作要去做了。</li>
</ul>
</blockquote>
<p><strong>使用情景：</strong></p>
<blockquote>
<ul>
<li>在大型工程或者文件的时候使用头文件的预编译器是<strong>非常重要</strong>的。用它</li>
<li>对于一些通用的常用的操作或者文件可以放进去，但是频繁更改的那些内容就不要放进去了，每次进行重新的预编译是浪费时间的
。
主要是一些include，declaration就别放在这了把？</li>
<li>预编译的header可以对project中的所有cpp负责吗？还是需要include</li>
<li>但是那些特定的依赖项，对于专门操作或者环境的，我们还是放到特定的cpp中，这样会使得代码更加易读，也不会增加负担。实际上就是两方面的考量，特定的和通用的两种处理方式。实际<strong>上取决于依赖程度</strong>；</li>
</ul>
</blockquote>
<p><strong>Visual Studio中的使用方法</strong></p>
<ol>
<li>创建需要预编译的头文件<code>pch.h</code>;创建<code>pch.cpp</code> 包含<code>#include &quot;pch.h&quot;</code></li>
<li>右键pch.cpp属性：c/c++ -&gt;预编译头-&gt;预编译头（<code>使用</code>）</li>
<li>右键项目属性：
<ol>
<li>c/c++ -&gt;预编译头-&gt;预编译头（<code>使用</code>/create）</li>
<li>c/c++ -&gt;预编译头-&gt;预编译头文件（<code>pch.h</code>）</li>
</ol>
</li>
<li>试一下把，不对的话，再回来检查视频。（可以在vscode的设置里，project c++中设置编译时间输出）</li>
</ol>
<h3 id="build代码存储的文件结构">Build：代码存储的文件结构</h3>
<p>补充说明：VS侧栏的文件夹实际上只是分组，不是真实文件夹，所以我们在哪创建h和cpp都一样</p>
<p><strong>Rule1:</strong> 推荐<strong>在header中只实现Declaration</strong>，而具体<strong>的Definition就只在某一个cpp中</strong>进行编写。</p>
<p>**Relu2：**在大型或者规范的Project中建议修改Vscode 的文件保存设置，当然我们也可以根据自己的需求去修改。</p>
<blockquote>
<p>输出目录： $(SolutionDir)bin$ (Platform)$(Configuration)\</p>
<p>中间目录： $(SolutionDir)bin\intermediate$ (Platform)$(Configuration)\</p>
</blockquote>
<h3 id="build-宏macros">Build: 宏（Macros）</h3>
<p><code>#define</code>的各种用法；实际上就是通过预处理器对某些操作进行宏处理，“我不喜欢过度使用宏，这样可能比较不方便阅读”这点上其实和template是一样的道理。</p>
<blockquote>
<p><code>#define</code> : 实际上就是在代码中搜索指定的文本进行替换</p>
<p>是一种文本级别的操作</p>
</blockquote>
<p><strong>推荐的使用方法：</strong></p>
<p>约定俗称的名称或者表达，或者一些简单的函数（但是实际上为了便于阅读，并不是太推荐，见仁见智把）</p>
<ul>
<li>
<p><code>#define pi=3.14159265</code>:类似的一种约定俗称的value</p>
</li>
<li>
<p><code>#define LOG(x) std::cout&lt;&lt;x&lt;&lt;std::endl;</code></p>
</li>
</ul>
<h3 id="debug条件与动作断点">Debug：条件与动作断点</h3>
<p><strong>基本操作：</strong></p>
<ul>
<li>设置breakpoint</li>
<li>内存信息读取：从debug-windows中可以调出各种窗口，从变量名或者&amp;para找到内存地址也可以</li>
</ul>
<p><strong>条件与动作断点：</strong></p>
<p>当然我们可以在代码中嵌入循环来使用普通断点来实现这些，简单的就是在断点的地方使用右键。主要的优势在于，我们无需暂停我们正在运行的程序，就可以执行这样的Break.</p>
<p><strong>Conditional</strong>：条件断点就不说了。</p>
<p><strong>Action</strong>：就是不需要stop我们的运行，我们添加了以后，就能在执行我们断点的操作的时候，在terminal输出，我们设置的action（简单的来说就是用于监控运行过程中的参数变化）</p>
<h3 id="lib-using-libraries-外部依赖的使用">Lib： Using Libraries 外部依赖的使用</h3>
<p><u>Static Linking and Dynamic Linking静态与动态链接库</u></p>
<p><strong>基本思想</strong>：希望在C++中不需要进行Package Manage 也就是不需要自己再去一个个的下载依赖项，也就是希望能pull下来就能用。</p>
<p>以GLFW为例，我们下载的时候可以下载2进制文件也可以下载源代码；下载的时候是x86还是x64与编写的目标代码有关，和OS无关。</p>
<h4 id="动态静态连接的基本概念">动态静态连接的基本概念</h4>
<p>静态链接在编译的时候实现，而动态链接是在运行的时候才操作；</p>
<ul>
<li>
<p><strong>静态链接</strong>，意味着这个库直接放到可执行文件中（比如说exe）</p>
<ul>
<li>静态链接在一些情况下会更快，而且我们可以进行各种优化，所以这个作者比较喜欢静态优化。</li>
<li>静态链接可以实现更多的优化操作，实际上是你exe中的一部分</li>
</ul>
</li>
<li>
<p><strong>动态链接</strong>，在运行的时候加载DLL（动态链接库）之类的。</p>
<ul>
<li>
<p>询问dll载入调用到的函数，静态lib就是一次性把所有的都载入了</p>
</li>
<li>
<p>它实现在运行过程中，linking一个外部文件，而不是可执行文件的一部分。</p>
</li>
<li>
<p>当然也可以在你启动电脑的时候就启动，也可以设置为require，就是没链接就会完全报错。</p>
</li>
</ul>
</li>
</ul>
<h4 id="静态和动态连接的具体实现">静态和动态连接的具体实现</h4>
<p>**静态链接的具体实现：**Head File，Include file的形式</p>
<ul>
<li>
<p>创建dependency文件夹然后-&gt;libraries子文件夹(归属关系)</p>
</li>
<li>
<p>Copy <code>include</code> 和相关vs版本的<code>lib</code>文件夹进去</p>
<ul>
<li>如果我们使用静态链接就和lib有关，如果我们使用动态链接就和DLL有关。</li>
</ul>
</li>
<li>
<p>在VS 设置中c++ general +额外包含文件夹+相对文件夹（${SolutionDir} -&gt;include文件夹）的路径</p>
<ul>
<li>如果需要我们也能在这看到其他的指代路径的意思</li>
</ul>
</li>
<li>
<p>然后include&lt;GLFW/…h&gt;     (其实使用双引号也没问题)</p>
<ul>
<li>这个头文件实际上支持动态链接和静态链接（include中的）</li>
<li>这里提供了declaration，但是没有实际的definition，所以我们还需要</li>
</ul>
</li>
<li>
<p>VS设置Linker/general/ Addition Libraries设置相对路径(Lib-vsxxx)和刚刚类似</p>
</li>
<li>
<p>VS设置Linker/Input/Additional Dependencies设置具体lib文件的地址</p>
</li>
<li>
<p>Over</p>
</li>
</ul>
<p><strong>第二种静态链接的方法(不推荐)</strong>
在前面的库设置好了以后，我们也可以不include，但是我们要声明（declaration）这个函数存在，注意类型不能错（这就好麻烦）</p>
<p>需要注意的是，我们链接的有的函数实际上是c而不是c++，这种时候就要添加前缀：</p>
<p>Extern &ldquo;C&rdquo;</p>
<p><strong>动态链接的具体实现</strong>：基于静态的实现来分析</p>
<p>dll和dll.liB需要同时使用，lib提供了一堆指向dll文件中函数的指针，两者直接相关。</p>
<ul>
<li>也就是相对于静态链接改变dependency中lib文件为dll.lib</li>
<li>然后要把dll放在我们需要运行的exe的同一个文件夹下。</li>
</ul>
<h3 id="libmultiple-project-编写自己的lib或dll">Lib：Multiple Project 编写自己的Lib或Dll</h3>
<p>在解决方案Title下可以添加项目，一个解决方案下多个project</p>
<ol>
<li>
<p>将主project的属性中配置类型设置为exe</p>
</li>
<li>
<p>将依赖文件设置为lib 或者dll，所有的配置和平台</p>
</li>
<li>
<p>同样的在h中下写declaration在cpp中definition，然后在include的时候，由于路径不在一个文件夹下，所以我们可以用相对路径的方式设置，但是这样就比较傻，正确的做法：👇</p>
</li>
<li>
<p>属性，c++通用，额外的包含目录，把该目录放进去就行了</p>
</li>
<li>
<p>但是这样其实我们没link，所以我们可以通过再主项目中右键添加引用，把我们要的引用添加进去，就可以了。（当然我们也可以生成lib再用）</p>
</li>
<li>
<p>但是这种情况好像只适用于同一个项目文件夹的时候。
这种自动处理同时会自动执行engineer的build</p>
</li>
</ol>
<p><strong>在这里使用了namespace的写法，也许就是和类中的函数是特别像的把，也就是std那样的双冒号</strong></p>
<h3 id="libtiming-计时器">Lib：Timing 计时器</h3>
<p>C++中的计时器功能：主要用于统计程序运行时间和控制进程等等的操作。</p>
<p>具体还有timer的cast还有一些单位转化的工作，去cpp中查找或者看benchmark那课的视频</p>
<p>主要使用的库：<code>#include&lt;chrono&gt;</code></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="c1">// 还有一个暂时不知道起什么作用的namespace
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="o">::</span><span class="n">literals</span><span class="o">::</span><span class="n">chrono_literals</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 获取当前的时间
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">auto</span> <span class="n">start</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">high_resolution_clock</span><span class="o">::</span><span class="n">now</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 获取时间间隔的方式，这里的type比较特别
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">duration</span><span class="o">&lt;</span><span class="kt">float</span><span class="o">&gt;</span> <span class="n">duration</span> <span class="o">=</span> <span class="n">end</span> <span class="o">-</span> <span class="n">start</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>上面这个方式,如果每次都要调用的话，就写得比较麻烦，如果我们希望能够比较简单的得到比如某个function运行的时间，我们可以利用lifetime签署一个类别，在function开始的时候定义一个就可以了。</p>
<p>看下面的实例：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">Timer</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">time_point</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">steady_clock</span><span class="o">&gt;</span> <span class="n">start</span><span class="p">,</span> <span class="n">end</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">duration</span><span class="o">&lt;</span><span class="kt">float</span><span class="o">&gt;</span> <span class="n">duration</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">Timer</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">start</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">high_resolution_clock</span><span class="o">::</span><span class="n">now</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="o">~</span><span class="n">Timer</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">end</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">high_resolution_clock</span><span class="o">::</span><span class="n">now</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="n">duration</span> <span class="o">=</span> <span class="n">end</span> <span class="o">-</span><span class="n">start</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// std::endl 实际上比较慢
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="o">&lt;&lt;</span><span class="s">&#34;timer took&#34;</span><span class="o">&lt;&lt;</span> <span class="n">duration</span> <span class="o">&lt;&lt;</span><span class="s">&#34;s</span><span class="se">\n</span><span class="s">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="libsort排序iterator">Lib：Sort排序iterator</h3>
<p><code>std::sort</code> need to <code>include&lt;algorithm&gt;</code> ；这是c++标准库中一个对Iterator进行排序的库。</p>
<p>复杂度 O(N·log(N))，其中N=<code>std::distance(first,last)</code></p>
<p>参考网站：https://zh.cppreference.com/w/cpp/algorithm/sort</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="c1">//简单实例
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="cp">#include&lt;vector&gt;
</span></span></span><span class="line"><span class="cl"><span class="cp">#include&lt;algorithm&gt;
</span></span></span><span class="line"><span class="cl"><span class="cp">#include&lt;functional&gt; </span><span class="c1">//其中有一些分类的标准可以调用
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">verctor</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">values</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">6</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">sort</span><span class="p">(</span><span class="n">values</span><span class="p">.</span><span class="n">bagin</span><span class="p">(),</span><span class="n">values</span><span class="p">.</span><span class="n">end</span><span class="p">());</span> <span class="c1">//空载或者&lt;,&gt;是基本的用法
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">//如果我们试图自定义函数的话
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">std</span><span class="o">::</span><span class="n">sort</span><span class="p">(</span><span class="n">values</span><span class="p">.</span><span class="n">bagin</span><span class="p">(),</span><span class="n">values</span><span class="p">.</span><span class="n">end</span><span class="p">(),[](</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">a</span><span class="o">==</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">False</span><span class="p">;</span> <span class="c1">//1放到其他所有的后面
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">if</span> <span class="p">(</span><span class="n">b</span><span class="o">==</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> <span class="c1">// 同上
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">return</span> <span class="n">a</span><span class="o">&lt;</span><span class="n">b</span> <span class="c1">//升序
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            
</span></span><span class="line"><span class="cl">    <span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="part-2-变量的使用和定义">Part 2 “变量”的使用和定义</h2>
<p>In this section we‘ll introduce <strong>variables（data structure） in C++</strong>，主要是变量的声明和使用方式和用途，生存周期，存储空间，各种Keyword，类型转换。</p>
<h3 id="变量variables">变量（Variables）</h3>
<p><strong>As we know all datatype in machine is different number</strong>
实际上就是给机器指定存储的空间和解析的类型。</p>
<ul>
<li>Char 实际上只是内联了“<strong>数字到字符的转换</strong>”，所以我们可以用各种类型来输入字符或数字（主要是内存空间占用），但是最后表达的类型会根据我们预定义的类型相关，有内联的数字和字符的转换存在。</li>
</ul>
<h4 id="基本的数据类型">基本的数据类型</h4>
<p>实际上就是预先定义了内存的分配了表达的类型，大小实际上取决于编译器。</p>
<p>可以用<code>sizeof()</code>查看各种<strong>类型</strong>占用的内存空间大小</p>
<p><strong>Keyword：</strong></p>
<blockquote>
<p><strong>整型：</strong></p>
<p>​	char（1 byte）；shot；int（4 byte）；Long；Long long（8 btyte）</p>
<p>​	unsigned</p>
<p><strong>非整型：</strong></p>
<p>​	Float（4 byte）；double（8 byte）</p>
<p>​	实际上是精度类型，比如再数据后面+f指定精度类型</p>
<p><strong>BOOL：</strong></p>
<p>​	bool （true， false == 0）；!0 即True</p>
<p><strong>Void：</strong></p>
<p>​	类型未指定</p>
</blockquote>
<p><strong>特殊类型</strong></p>
<ul>
<li>指针类型（Pointers）：再类型后面+ <code>*</code>: <code>int* variables</code></li>
<li>引用类型和取值符号（reference）：
<ul>
<li>引用： 在类型后面+<code>&amp;</code>:<code>int&amp; refer</code></li>
<li>取址：<code>int* a = &amp;variable;</code></li>
</ul>
</li>
</ul>
<h4 id="变量的作用域和生命周期">变量的作用域（{}）和生命周期</h4>
<p><strong>作用域</strong>：在哪个范围内能访问到该变量</p>
<p><strong>生命周期</strong>：</p>
<ul>
<li>在内存中存在的范围（stack变量一般是活不过<code>}</code>）</li>
<li>需要跨越作用域的生存的话通常需要指定存储heap</li>
</ul>
<h4 id="object对象的生命周期">object“对象”的生命周期</h4>
<p>（<strong>不使用New关键词的时候</strong>）生命周期只到栈或者说是<strong>大括号</strong>内（可以使用空的大括号组），是存在的</p>
<p>（<strong>使用new关键词的时候</strong>）如果我们不delete它，就只能在程序终止的时候才退出了。</p>
<p>:x: 下面这是一种<u>十分错误</u>的写法</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">int</span><span class="o">*</span> <span class="nf">CreateArray</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">array</span><span class="p">[</span><span class="mi">50</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">array</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">array</span><span class="p">[</span><span class="mi">50</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="n">CreateArray</span><span class="p">(</span><span class="n">array</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">//完全错误，在函数结束的时候这个指针会被完全销毁，所以指向的地址是没有值的，
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果我们希望延长声明周期，我们可以将数据分配到heap上，或者通过传入指针，对指针调用的地址的值进行修改。</p>
<p><strong>编写一个会自己销毁的在heap上的指针</strong>（实际上和智能指针又异曲同工之妙）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">ScopedPtr</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 该ScopedPtr的申明是存在stack上的，所以销毁的时候调用delete就直接。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">private</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">Entity</span><span class="o">*</span> <span class="n">m_ptr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">ScopedPtr</span><span class="p">(</span><span class="n">Entity</span><span class="o">*</span> <span class="n">ptr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="o">:</span><span class="n">m_ptr</span><span class="p">(</span><span class="n">ptr</span><span class="p">){}</span>
</span></span><span class="line"><span class="cl">    <span class="o">~</span><span class="n">ScopedPtr</span><span class="err">（）</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">delete</span> <span class="n">m_ptr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">ScopedPtr</span> <span class="n">e</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Entity</span><span class="p">();</span> <span class="c1">//申明周期也只到内部的大括号，出不去。会顺便把实例也销毁了。这个还稍微有点疑问。:question
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="const-常量修饰符">const 常量修饰符</h4>
<p><a href="https://www.runoob.com/w3cnote/cpp-const-keyword.html" target="_blank" rel="noopener">C++ const 关键字小结 | 菜鸟教程 (runoob.com)</a>
</p>
<p><strong>语义含义</strong>：<strong>不可变，不可修改</strong>；</p>
<ul>
<li>可以令值不可变，也可以令指针不可变；定义一些常量之类的东西</li>
<li>可以在函数传入值中定义，使得传入值不可被修改，或者防止传入的指针或者是引用被不正确的修改导致一些奇怪的问题。</li>
<li>要注意根据位置的不同是指针不可修改还是值不可修改的含义是不一样的。</li>
</ul>
<p><strong>本质含义</strong>：实际上是一种代码的可见性机制，只是个promise，用来简化我们的代码。所以我们应该遵守它：就是我们不去修改这个const。（避免使用强制类型转换去修改它）</p>
<p>几种基本的定义方式：</p>
<ol>
<li>
<p>这种形式指的是我们<strong>没法修改地址的值</strong>，但是我们可以改变指针所指向的地址。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="c1">//这两种都是一样的，在指针*的前面
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">const</span> <span class="kt">int</span><span class="o">*</span> <span class="n">a</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span> <span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="k">const</span><span class="o">*</span> <span class="n">a</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span> <span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>这种形式指的是<strong>无法修改</strong>指针引用的那个<strong>地址</strong>，但是可以随意的修改值。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">int</span><span class="o">*</span> <span class="k">const</span> <span class="n">a</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span> 
</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>复用就是都不能改</p>
</li>
<li>
<p>在类中的public函数declaration的括号后面加 const，指的是我们<u>没法在类内函数中修改类内的private的值</u>。这样的操作会被定义为illegal。</p>
</li>
<li>
<p>类内指针的话就有意思了，要有三个const全用
:question:这一点后面慢慢补充，没搞清楚来着，记得太模糊了。</p>
</li>
<li>
<p><code>const Entity&amp; e</code> 指的是我们<strong>没法修改指向的地址</strong>。</p>
</li>
</ol>
<p><strong>实例说明：</strong></p>
<p>对于传入函数的Instance（Entity）也是一样的，如果我们不希望进行内存上的copy，我们就加上&amp;，如果我们不希望改变值就加入const。</p>
<p>用一些例子来说明一些其他情况的Const用法。 需要注意！</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Entity</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">m_x</span><span class="p">,</span> <span class="n">m_y</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">GetX</span><span class="p">()</span> <span class="k">const</span> <span class="c1">//需要保证函数不能修改类内的private的值
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">m_x</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 但是还是有一些问题
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="err">在这种情况下的</span><span class="n">const最前面的就是指的指针的地址不能变</span><span class="err">，但是其中的值能变。那么在这个时候，涉及到实体的那些函数，如果我们再类中没有加入</span><span class="n">const后缀的话</span><span class="err">，那么我们就不能使用这个</span><span class="n">get函数</span><span class="err">，因为编译器不能确保他不修改我们不能动的那些数据。</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl"><span class="err">所以有时候会出现一个</span><span class="o">+</span><span class="n">const的定义和一个不加const的定义</span><span class="err">。</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl"><span class="err">如果我们对一些</span><span class="n">private需要指定在一些const后缀的情况下可以改变</span><span class="err">，那么我们可以再声明的时候加入</span><span class="n">mutable前缀</span><span class="err">：允许的可变。</span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">PrintEntity</span><span class="p">(</span><span class="k">const</span> <span class="n">Entity</span><span class="o">&amp;</span> <span class="n">e</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">e</span><span class="p">.</span><span class="n">GetX</span><span class="p">()</span><span class="o">&lt;&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="mutable可变标识符">Mutable可变标识符</h4>
<p>**用途1：**基本上对于一些private类，在有const后缀的情况下我们又希望修改其中的某个值，才会用到这个关键词。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">A</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">m_name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">mutable</span> <span class="kt">int</span> <span class="n">m_DebugCount</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 结合上面的范例可以看出这个返回类型为啥回事这个const+&amp;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">GetName</span><span class="p">()</span> <span class="k">const</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">m_DebugCount</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">m_name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>用途2：<strong>使用</strong>lambda</strong>的时候。我们希望能够修改传入值本身，（但是lambda是不允许修改的所以需要）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">f</span> <span class="o">=</span> <span class="p">[</span><span class="o">=</span><span class="p">]()</span> <span class="k">mutable</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">x</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">x</span><span class="o">&lt;&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">f</span><span class="p">();</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="static静态标识符">Static静态标识符</h4>
<p><strong>静态标识符类型：</strong> class or struct 内部，外部，function 内</p>
<p><strong>类外的static：</strong></p>
<p>对于Linker起作用的修饰符，表示为<strong>局部的</strong>，也就是<strong>只对它本身的obj</strong>起作用，不会和别的文件连接起来，只对本身可见。</p>
<blockquote>
<ul>
<li>
<p>如果在<strong>function</strong>的前面添加Static 就表示该Function 只被该.cpp调用，也不会考虑外部的Link，所以当我们如果希望被外部调用的时候就不能加static标识符，在要调用的地方进行<strong>declaration.</strong></p>
</li>
<li>
<p>实际上<strong>全局的参数定义</strong>，对于Linker来说也可以是跨文件的，所以如果我们定义全局参数的话，我们要考虑是否是通用的（需要重复include的常量），就可只在cpp定义一次。同时我们要在引用（另一个文件）的时候添加修饰符。（比如在头文件中用Extern Declaration参数）</p>
<p><strong>Extern</strong>（也是用于声明：在外部已经定义过了，定义参数独有的）</p>
<p><a href="https://www.cnblogs.com/lulululu/p/3693865.html" target="_blank" rel="noopener">https://www.cnblogs.com/lulululu/p/3693865.html</a>
</p>
</li>
</ul>
</blockquote>
<p><strong>类内的static：</strong></p>
<p><strong>这部分*memory</strong>对于这个类别的所有实例<strong>是共享</strong>的，换句话说也就是，无论你定义了多少个instances，这个变量或者方法也是唯一的，对于所有的类别是通用的。你<strong>改变了一个，也就改变了所有。</strong></p>
<blockquote>
<ul>
<li>所以，类内的静态方法可以在没有类实例的情况下被调用，而且在这种静态方法中不能refer to 一个具体的类实例。</li>
<li>也不能通过<strong>实例对静态变量进行调用处理</strong>，这样Linker会找不到我们实例对应的变量，因为那几个变量是类的变量而不是实例的变量。那么怎么去调用或者修改呢。</li>
<li>使用作用域(type  ClassName:: x)的方式去声明,同样也<strong>以这样的方式去调用</strong>（ClassName（同样也能类比成namespace）:: x）才是真正正确的使用方法，类内的静态函数也是这样定义和操作的。但是<strong>不用</strong>像参数一样在类外声明</li>
</ul>
</blockquote>
<p><strong>Function内的Static：</strong></p>
<blockquote>
<ul>
<li>其实和类内的Static是一样的，当我们第一次调用这个function的时候就会存储这样一个对于所有的function的静态变量，后续调用的时候这个参数就<strong>不会被重新创建</strong>了。</li>
<li>也就是说这种<strong>参数对于函数来说是恒定</strong>的，在该参数上进行的<strong>变化会被继承</strong>下来，也就是会被迭代运作。</li>
<li>某种程度上来说也算是延长了参数的生命周期，通常来说需要&amp;的return值的一些情况下就需要用static关键词定义的vars。(:question:这一点是啥意思来着）</li>
</ul>
</blockquote>
<h3 id="数组多维变量array">数组、多维变量（Array）</h3>
<h4 id="经典数组">经典数组</h4>
<p>数组实际上是一组连续的变量，在内存上存储指定长度的空间，<strong>本质是指针</strong></p>
<ul>
<li>
<p><strong>定义方式</strong>：<code>type var[n]</code>,定义n个<strong>连续</strong>的type<strong>内存空间</strong>，这里的var实际上是相应的<strong>指针</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">example</span> <span class="p">[</span><span class="mi">5</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span><span class="o">*</span> <span class="n">ptr</span> <span class="o">=</span> <span class="n">example</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>用var[idx]去索引指针相应地址的值：（实际上就是在初始地址上加上相应的偏移）</p>
</li>
<li>
<p>默认在stack上：没有new就是在stack上，需要heap就＋new把 记得delete[]</p>
<blockquote>
<p>同时也可以用New关键字去声明数组，同时这个数组就会被存储到Heap中，这样的话该数组的声明周期就能活过大括号了，需要我们手动调用delete命令去删除它，由于定义的形式是数组所以在delete的时候记得使用的是delete[] var 命令</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">int</span><span class="o">*</span> <span class="n">another</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="p">[</span><span class="mi">5</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span><span class="mi">5</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="n">another</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></blockquote>
</li>
</ul>
<p>和传统的array好像有一定的同质性；找到数组长度的方法：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">count</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">/</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">int</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 用std::array的会自己保存数据的array
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="静态数组stdarray">静态数组（std::array）</h4>
<p><strong>数组的长度或者大小没办法自动（动态）改变的</strong>，我们应该用这种方式来代替传统的定义方式，有很多好处。</p>
<p><a href="https://blog.csdn.net/thinkerleo1997/article/details/80415059" target="_blank" rel="noopener">https://blog.csdn.net/thinkerleo1997/article/details/80415059</a>
</p>
<p><a href="https://blog.csdn.net/fengbingchun/article/details/72809699" target="_blank" rel="noopener">https://blog.csdn.net/fengbingchun/article/details/72809699</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="cp">#include&lt;array&gt;
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="n">std</span><span class="o">::</span><span class="n">array</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="mi">5</span><span class="o">&gt;</span> <span class="n">data</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>什么时候我们应该用这种array来取代传统的int array？</strong></p>
<ul>
<li>现在这种方式有很多的集成函数：比如说size，sort，began好像还有iterator之类的方法。</li>
<li>因为传统的使用New，关键词是slow的，这种方法也会快一点，而且长度是不知道的。</li>
<li>verctor是heap上的，而array和传统的int，array都是存在在stack上的，（非new关键词）</li>
<li>有很多优化，同时这种方法有自动的边界检测？</li>
<li>在函数传入array的时候，建议可以使用template的方法。</li>
</ul>
<p>**BTW：**快不是标准库（STD）的基本目的和最求，所以很多时候需要资源最大化利用的情况下，很多project都会编写自己的数据类型：（可以从Cherno的最后两课去看看）</p>
<h4 id="动态数组stdvector">动态数组（std::vector）</h4>
<p>更详细的一些操作指南可以google或者看HR的<code>vector.svg</code>(附件)</p>
<p>就是个不指定大小的Array，可以改变数组的大小，其实就是自动执行内存的重新分配（内存动态分配），牺牲性能来得到更好的便捷性。</p>
<blockquote>
<p>虽然C++命名Vector，但是实际上是个动态的ArrayList，而不是向量。</p>
</blockquote>
<p><strong>vector移动数据</strong>而不是Copy的方式在很大程度上提升了效率（没超过默认大小的情况下），但是在超过了指定大小的时候，还是需要用到copying（内存的动态分配）这就不是一个非常理想的情况。</p>
<blockquote>
<p>Vector：当append超过了现有的容量，找到一个足够大的内存位置，然后把原本的参数copy迁移过去，然后加上我们要添加的参数，然后删除原本占用的内存空间。</p>
<p>这样就会造成运行缓慢，那么我们如何<strong>避免这样的copy操作</strong>，</p>
</blockquote>
<p><a href="https://blog.csdn.net/theonegis/article/details/50533770" target="_blank" rel="noopener">https://blog.csdn.net/theonegis/article/details/50533770</a>
</p>
<p><strong>基本的声明方式</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include&lt;vector&gt;
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">type</span><span class="o">&gt;</span><span class="n">name</span><span class="p">;</span> <span class="c1">//type 也可以是自己定义的class；实际上存储的就是数据的内存顶点（起始点）
</span></span></span><span class="line"><span class="cl"><span class="c1">// using vector = std::vector以后
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">vector</span> <span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">a</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">b</span><span class="p">(</span><span class="n">a</span><span class="p">);</span> <span class="c1">//声明容器b, 用容器a初始化b
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">b</span><span class="p">(</span><span class="n">a</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="n">a</span><span class="p">.</span><span class="n">begin</span><span class="p">()</span><span class="o">+</span><span class="mi">3</span><span class="p">);</span> <span class="c1">//用0-2个元素来初始化
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">vector</span> <span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">a</span><span class="p">(</span><span class="n">num</span><span class="p">);</span> <span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">vector</span> <span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">a</span> <span class="p">(</span><span class="n">num</span><span class="p">,</span><span class="n">value</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>基本的一些method</strong></p>
<p><code>Push_back({v1,v2,v3})</code> 就相当于append；<code>size（）</code>获取长度；<code>clear（）</code>将长度设置为0</p>
<p>索引还是[]；</p>
<p><code>eraser（）</code>：需要在括号中设置一个迭代器，比如我们需要移除第二个参数</p>
<p>​           ↑：<code>vertices.begin() +1</code></p>
<p>使用示例：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">Vertex</span><span class="o">&gt;</span> <span class="n">vertices</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">vertices</span><span class="p">.</span><span class="n">push_back</span><span class="p">({</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="n">vertices</span><span class="p">.</span><span class="n">push_back</span><span class="p">({</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">vertices</span><span class="p">.</span><span class="n">size</span><span class="p">();</span><span class="n">i</span><span class="o">++</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">Print</span><span class="p">(</span><span class="n">vertices</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="n">vertices</span><span class="o">&amp;</span> <span class="nl">v</span><span class="p">:</span> <span class="n">vertices</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">Print</span><span class="p">(</span><span class="n">v</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>存储空间</strong></p>
<p>默认应该是在heap上的，但是会自动删除的。</p>
<p><strong>优化vector的使用</strong></p>
<p><strong>issue1：<strong>我们会先调用最原始的构造函数，在main function的栈中构造一个vectex，然后copy it to Vertor类所在的空间中，如何</strong>直接</strong>在<strong>指定的地方添加</strong>（或者说只进行一次构造）呢？</p>
<p>解决方法：用<code>emplace_back </code>取代<code>push_back</code>,<strong>直接传入构造对象需要的参数</strong>即可</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">vetrices</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">vetrices</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">vetrices</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">));</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>**issue2:**空间超过以后进行了复制和迁移操作，也就是我们每一次添加都需要把原本的空间进行resize（copy and move）</p>
<p>解决方法：直接在开始的时候指定可能的最大size，就是给定一个<a href="https://www.cnblogs.com/zhuruibi/p/8983192.html" target="_blank" rel="noopener">预留空间</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">Vertex</span><span class="o">&gt;</span> <span class="n">Vertices</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">Vertices</span><span class="p">.</span><span class="n">reserve</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="字符串string">字符串（String）</h3>
<p><strong>String - stream of text 一组字符串 == array of characters</strong></p>
<p><strong>一些额外的信息</strong>：字符串相关的一些其他事项</p>
<ul>
<li>
<p>实际上<code>&quot;&quot;</code>定义的就是固定（const）的type为char的指针，也就是 const char*；换句话说也就是占据固有长度的char array</p>
</li>
<li>
<p>实际上这是c中编写string的风格，为了熟悉基本的原理才这么编写的，现在就直接用string库了</p>
</li>
<li>
<p>原本定义的时候还需要在末尾指定ascii码终止符，但是在新的版本中不需要特地指定，也就是下述的两者是一样的。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">char</span> <span class="n">name2</span><span class="p">[</span><span class="mi">7</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="sc">&#39;A&#39;</span><span class="p">,</span><span class="sc">&#39;i&#39;</span><span class="p">,</span><span class="sc">&#39;k&#39;</span><span class="p">,</span><span class="sc">&#39;e&#39;</span><span class="p">,</span><span class="sc">&#39;n&#39;</span><span class="p">,</span><span class="mi">0</span><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="kt">char</span> <span class="n">name2</span><span class="p">[</span><span class="mi">7</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="sc">&#39;A&#39;</span><span class="p">,</span><span class="sc">&#39;i&#39;</span><span class="p">,</span><span class="sc">&#39;k&#39;</span><span class="p">,</span><span class="sc">&#39;e&#39;</span><span class="p">,</span><span class="sc">&#39;n&#39;</span> <span class="p">};</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
</ul>
<p><strong>基本信息</strong>: 使用string的基本注意事项</p>
<ul>
<li><strong>基本的定义方式也就是和int之类的没区别</strong></li>
<li><strong>string类别</strong>就可以使用find size append +=之类的操作了，所以拥抱string；
官方的<a href="http://www.cplusplus.com/reference/string/string/" target="_blank" rel="noopener">参考链接地址</a>
（看看其中的function的作用）：</li>
<li><code>&quot;&quot;</code>定义的类别实际上就是<code>const char[]</code>，本身就是一个不可修改的指针了，各种意义上的不可修改</li>
<li><code>''</code>定义的才是像普通的123这样的char value</li>
<li><code>string</code>实际上也是<code>std</code>中的一部分: 同时include它包含了重载&laquo;，使得其得以接受stiring类型。</li>
<li>+=不能再“”中执行，但是可以在string和“”中进行。</li>
<li>将string 传入函数的时候，也是不修改原值的，所以我们还是使用<code>&amp;</code>的传入参数设置去使得不需要赋值一个新的，同时如果不希望修改的话，就在最前面加入<code>const</code></li>
</ul>
<p><strong>String Literals</strong></p>
<ul>
<li>实际上我们在上面说的“”定义的就是String     Literals，字符常量，这种方式定义的后面会自带一个休止符的位置，再内存中也就是00；我们也可以手动定义休止符\0</li>
<li>实际上我们修改string都是再内存中获取一个Copy去进行的。所以我们需要善用&amp;符号</li>
</ul>
<p><strong>一些函数：</strong></p>
<p>Strlen（）:返回string长度，char array，要注意自己手写休止符的特殊情况</p>
<p>基本的“”实际上也是utf-8类型的。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">name</span> <span class="o">=</span> <span class="sa">u8</span><span class="s">&#34;Aiken&#34;</span><span class="p">;</span> <span class="c1">//1 byte
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">const</span> <span class="n">wchar</span><span class="o">*</span> <span class="n">name2</span> <span class="o">=</span> <span class="sa">L</span><span class="s">&#34;Aiken&#34;</span><span class="p">;</span> <span class="c1">// (2/4) byte
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">const</span> <span class="kt">char16_t</span><span class="o">*</span> <span class="n">name3</span> <span class="o">=</span> <span class="sa">u</span><span class="s">&#34;Aiken&#34;</span><span class="p">;</span> <span class="c1">// 2 byte
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">const</span> <span class="kt">char32_t</span><span class="o">*</span> <span class="n">name4</span> <span class="o">=</span> <span class="sa">U</span><span class="s">&#34;Aiken&#34;</span><span class="p">;</span> <span class="c1">//4 byte
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以使用</p>
<ul>
<li><code>using namespace std::string_literals</code>使得我们对 <strong>“” -&gt; string</strong>的类型转换可以从
<code>std::string(&quot;&quot;)</code>变成只需要<code>&quot;&quot;s</code></li>
<li>R&rdquo;&quot; 也很有用，:question:但是我忘了这个是用来干嘛的了</li>
</ul>
<h3 id="枚举类型enums">枚举类型（ENUMS）</h3>
<p>枚举类型：也就是set of value</p>
<p>根据第一个var = x; 后面每一项的默认值在前一项的基础上+1，自动匹配对应的value</p>
<p>本质上就是一组指定的别名和其对应的value</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">example</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">enum</span> <span class="nc">Level</span><span class="o">:</span> <span class="kt">unsigned</span> <span class="kt">char</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">L_error</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span><span class="n">L_Warning</span><span class="p">,</span><span class="n">L_info</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="c1">//取代了下面这种表达其实
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">    const int L_error = 0;
</span></span></span><span class="line"><span class="cl"><span class="cm">    const int L_warning = 1;
</span></span></span><span class="line"><span class="cl"><span class="cm">    const int L_info = 2;
</span></span></span><span class="line"><span class="cl"><span class="cm">    */</span>
</span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">Level</span> <span class="n">m_logLevel</span> <span class="o">=</span><span class="n">L_info</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="自动类别指定auto-keyword">自动类别指定（Auto Keyword）</h3>
<p><strong>可以结合模板来使用</strong></p>
<p>实际上就是根据我们键入的等式右边的内容，自动指定int float or any other type。</p>
<blockquote>
<p>但是作者不是很推荐这种用途，很简单的情况，就很没必要，而且不利于阅读和维护<code>auto a = 4;</code></p>
</blockquote>
<p>比较推荐的用法：</p>
<ol>
<li><strong>调用函数时的返回值前缀</strong>：</li>
</ol>
<ul>
<li>
<p>在这种情况下我们修改function（API）的return type的时候就不需要重新在<strong>修复赋值</strong>的定义了，这种时候auto还是很有用的，或者<strong>返回类型不明确</strong>的时候。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="c1">// 比如function的type 我们可能经常会动，或者有几个相似的函数的情况
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kt">char</span><span class="o">*</span> <span class="nf">GetName</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s">&#34;aiken&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">auto</span> <span class="n">name</span> <span class="o">=</span> <span class="n">Getname</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>缺点：但是这种方式的话实际上也会让我们是否修改了代码的指示比较不明确，比如有时候会发生隐式转换。</p>
</li>
</ul>
<ol start="2">
<li>
<p><strong>替代特别长的数据类型：</strong>
比如使用像vector这种的时候，参数名实在是太长了，就你懂的了，推荐使用（当然这种可以用using 来取代也是一样的。）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="c1">// 使用 using的话就是。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">using</span> <span class="n">DeviceMap</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">unordered_map</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">verctor</span><span class="o">&lt;</span><span class="n">Device</span><span class="o">*&gt;&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">DeviceManager</span> <span class="n">dm</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 话说下面这个应该是 值不可被修改的别名（因为&amp;本来就无法修改地址，所以只有一种可能把）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">coust</span> <span class="n">DeviceMap</span><span class="o">&amp;</span> <span class="n">devices</span> <span class="o">=</span> <span class="n">dm</span><span class="p">.</span><span class="n">GetDevices</span><span class="p">();</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
</ol>
<h3 id="模板templates">模板（Templates）</h3>
<p>模板可以理解为一种指代，简单的例子就是通过这种模板的定义我们可以定义一个类别通用的函数；</p>
<p>模板实际上是在编译的时候就实现的一种机制，而不是到了具体的运行的时候才实现的。</p>
<p><strong>简单使用场景：</strong></p>
<ol>
<li>当我们需要多种类型的输入，来进行相似的function操作，比如说Print的时候，这种时候我们定义一种TypeName的模板；然后我们就可以使用如下方式调用定义的函数了。</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">Print</span><span class="p">(</span><span class="n">T</span> <span class="n">value</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="o">&lt;&lt;</span> <span class="n">value</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">print</span><span class="p">(</span><span class="mi">5</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">print</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">(</span><span class="mi">5</span><span class="p">);</span> <span class="c1">//其他类型的也可以，只要函数内部支持就行。
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="2">
<li>除了不确定的类别，我们也可以针对不确定的size去做（其实这里的int类型可以改成size_t）</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="p">,</span> <span class="kt">int</span> <span class="n">N</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Array</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">T</span> <span class="n">m_array</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">Getsize</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span><span class="k">return</span> <span class="n">N</span><span class="p">;}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="c1">//main 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">Array</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="mi">5</span><span class="o">&gt;</span> <span class="n">array</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>但是不要过度使用，因为可读性会比较差；但是更关键的是，模板在编译和执行的时候是两回事，这样会让我们很难定位问题。所以不要乱用。但是在编写loging的system之类的地方，就比较合适。</p>
<h3 id="操作符与操作符重载operators-and-operator-overloading">操作符与操作符重载（Operators and operator overloading）</h3>
<p>需要注意的是，存在默认参数的函数不能进行重载，因为当默认参数存在，调用的时候可以忽略部分参数，这样在进行函数的调用的时候会产生歧义。</p>
<p>更多的表现是符号而不是函数，<code>new</code> ， <code>+</code> <code>-</code> ,之类的都是 括号</p>
<p>与或非： <code>||</code> <code>&amp;&amp;</code> <code>！</code></p>
<p><strong>一些优先级设定：</strong></p>
<p>++之类的运算符号的<strong>优先级</strong>&gt; *取值，所以我们要<strong>加入括号</strong>，使其首先解引用，防止改变的是地址的值而不是value。</p>
<p><strong>重载的用途：</strong></p>
<p>比如我们实现向量类别的时候，我们就可以重载+，来实现这个加号，就是不用写一个Add函数（麻烦），主要是比较大规模的情况下为了使用方便来写的吧。</p>
<p><strong>Example：</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">Vector2</span> <span class="nf">Add</span><span class="p">(</span><span class="k">const</span> <span class="n">Vector2</span><span class="o">&amp;</span> <span class="n">other</span><span class="p">)</span> <span class="k">const</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">Vector2</span><span class="p">(</span><span class="n">x</span> <span class="o">+</span> <span class="n">other</span><span class="p">.</span><span class="n">x</span><span class="p">,);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">Vector2</span> <span class="k">operator</span><span class="o">+</span><span class="p">(</span><span class="k">const</span> <span class="n">Vector2</span><span class="o">&amp;</span> <span class="n">other</span><span class="p">)</span> <span class="k">const</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nf">Add</span><span class="p">(</span><span class="n">other</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>为了更方便的cout重载<code>&lt;&lt;</code></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">ostream</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">&lt;&lt;</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">ostream</span><span class="o">&amp;</span> <span class="n">stream</span><span class="p">,</span> <span class="k">const</span> <span class="n">Vector2</span><span class="o">&amp;</span> <span class="n">other</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">stream</span><span class="o">&lt;&lt;</span> <span class="n">other</span><span class="p">.</span><span class="n">x</span> <span class="o">&lt;&lt;</span><span class="n">other</span><span class="p">.</span><span class="n">y</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">stream</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>对bool的判断进行重载：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">bool</span> <span class="k">operator</span><span class="o">==</span><span class="p">(</span><span class="k">const</span> <span class="n">Vector2</span><span class="o">&amp;</span> <span class="n">other</span><span class="p">)</span> <span class="k">const</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">x</span><span class="o">==</span><span class="n">other</span><span class="p">.</span><span class="n">x</span> <span class="o">&amp;&amp;</span> <span class="n">y</span><span class="o">==</span> <span class="n">other</span><span class="p">.</span><span class="n">y</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kt">bool</span> <span class="k">operator</span><span class="o">!=</span><span class="p">(</span><span class="k">const</span> <span class="n">Vector2</span><span class="o">&amp;</span> <span class="n">other</span><span class="p">)</span> <span class="k">const</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="o">!</span><span class="p">(</span><span class="o">*</span><span class="k">this</span> <span class="o">==</span> <span class="n">other</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>重载迭代器的索引</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">char</span><span class="o">&amp;</span> <span class="k">operator</span><span class="p">[](</span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">index</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">m_buffer</span><span class="p">[</span><span class="n">index</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="命名空间namespace">命名空间（Namespace）</h3>
<p>Using namespace apple (导入apple中所有的定义)</p>
<p>Using apple：：func1（只导入func1）</p>
<p>Namespace a = 定义</p>
<p>类似的查看cppreference网页即可</p>
<h3 id="左值与右值lvalue-and-rvalue">左值与右值（lvalue and rvalue）</h3>
<p>其实就是赋值等式左边的变量和右边的常量的关系把？在这部分还会讲到相应的reference。</p>
<p><u>rvalue就是 i=10中的10，这种值不能被更改，是一种临时的变量值，没有location和space，我们会将它分配到i，也就是左值。才是可分配和可改变的</u>。实际上就是这样的。</p>
<p>rvalue可以用来创建lvalue，<strong>lvalue才有reference</strong>，但是有特殊规则；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">int</span><span class="o">&amp;</span> <span class="n">a</span> <span class="o">=</span><span class="mi">10</span> <span class="c1">// error,这样写是错的，rvalue没有直接的引用
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">const</span> <span class="kt">int</span><span class="o">&amp;</span> <span class="n">a</span> <span class="o">=</span><span class="mi">10</span><span class="p">;</span> <span class="c1">//right
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>了解这点的意义在于（为啥我们要使用const）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="nl">std</span><span class="p">:</span><span class="n">string</span> <span class="n">fName</span> <span class="o">=</span> <span class="s">&#34;H&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nl">std</span><span class="p">:</span><span class="n">string</span> <span class="n">Lname</span> <span class="o">=</span> <span class="s">&#34;Aiken&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nl">std</span><span class="p">:</span><span class="n">string</span> <span class="n">Fullname</span> <span class="o">=</span> <span class="s">&#34;Aiken&#34;</span> <span class="o">+</span> <span class="s">&#34;H&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 这个等式左边的全lvalue, 等式右边的（整体）都是rvalue，于是我们调用下面函数的时候，无法写输入值为&#34;Aiken&#34; + &#34;H&#34;，因为rvalue没有&amp;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kt">void</span> <span class="nf">PrintFuc</span><span class="p">(</span><span class="nl">std</span><span class="p">:</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">name</span><span class="p">){}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 我们稍微修改一下，就能得到一个通用的Print,能够对临时变量rvalue进行传入。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kt">void</span> <span class="nf">PrintFuc</span><span class="p">(</span><span class="k">const</span> <span class="nl">std</span><span class="p">:</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">name</span><span class="p">){}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>假如我们需要一个<strong>只能传入rvalue</strong>的函数，那么我们可以将表达修改为，这是一种特殊的方式</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">PrintFuc</span><span class="p">(</span><span class="nl">std</span><span class="p">:</span><span class="n">string</span><span class="o">&amp;&amp;</span> <span class="n">name</span><span class="p">){}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这种方式有什么用呢？对于下面的<strong>移动语义</strong>很有用，因为<strong>临时的变量</strong>不需要考虑livetime或者memory之类的东西，同时我们可以简单的获取其中的值，<u>不用担心他和很多其他的地方产生关联。</u></p>
<h3 id="移动语义move-semantics">移动语义（move semantics）</h3>
<blockquote>
<p>**Question：**为什么&amp;引用符号不能解决这个问题，好像是对传入object的情况进行处理的一种方法：就像string，我们在某个地方需要她的时候，我们可能需要重新构造它。</p>
</blockquote>
<blockquote>
<p>**Ans：**移动语义针对的对象实际上是Rvalue，也就是临时变量，临时变量的生命周期短，特别是像“”到string的情况，也是需要申请空间的，这样在我们将rvalue传入function或者class的时候，就会发生一次不必要的copy（因为rvalue没有&amp;所以你懂的）</p>
</blockquote>
<p><strong>Move Semantic： move objects around</strong></p>
<p>为了避免类似的不必要copy的操作，我们就使用<strong>移动语义</strong>的编程思想来做。👇</p>
<p><u>move就是获取原本存储地址的指针，然后再将原本的指针赋值为nullptr（这样会使得其自动调用析构函数，也就不会有泄露等错误了）同时将size设置为0。</u></p>
<p><em>相比较于深拷贝实际上就是一种浅拷贝的操作。</em></p>
<p>具体的实现思路其实就是针对rvalue重构copy constructor</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="c1">//copy constructor 如下,以class string为例
</span></span></span><span class="line"><span class="cl"><span class="c1">//基础类别的部分
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">string</span><span class="p">(</span><span class="k">const</span> <span class="n">String</span><span class="o">&amp;</span> <span class="n">other</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">printf</span><span class="p">(</span><span class="s">&#34;Copird!&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">m_size</span> <span class="o">=</span> <span class="n">other</span><span class="p">.</span><span class="n">size</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">m_data</span> <span class="o">=</span> <span class="n">new_char</span><span class="p">[</span><span class="n">m_size</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="n">memcpy</span><span class="p">(</span><span class="n">m_data</span><span class="p">,</span> <span class="n">other</span><span class="p">.</span><span class="n">m_data</span><span class="p">,</span><span class="n">other</span><span class="p">.</span><span class="n">m_size</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">//重构rvalue情况下的..
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">string</span><span class="p">(</span><span class="k">const</span> <span class="n">String</span><span class="o">&amp;&amp;</span> <span class="n">other</span><span class="p">)</span> <span class="n">noexpect</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">printf</span><span class="p">(</span><span class="s">&#34;Move!&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">m_size</span> <span class="o">=</span> <span class="n">other</span><span class="p">.</span><span class="n">size</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">m_data</span> <span class="o">=</span> <span class="n">other</span><span class="p">.</span><span class="n">m_data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 清除原本的指针
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">other</span><span class="p">.</span><span class="n">size</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">other</span><span class="p">.</span><span class="n">m_data</span> <span class="o">=</span> <span class="k">nullptr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// Entity部分，要添加一个针对rvalue的构造函数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">Class</span> <span class="n">Entity</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="err">：</span>
</span></span><span class="line"><span class="cl">    <span class="n">Entity</span><span class="p">(</span><span class="k">const</span> <span class="n">String</span><span class="o">&amp;</span> <span class="n">name</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    	<span class="o">:</span><span class="n">m_name</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 这里注意要手动把转换写出来，不然还是会进行copy的情况(执行上面那个),move 或者(string&amp;&amp;)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">Entity</span><span class="p">(</span><span class="k">const</span> <span class="n">String</span><span class="o">&amp;&amp;</span> <span class="n">name</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    	<span class="o">:</span><span class="n">m_name</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">name</span><span class="p">))</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="k">private</span><span class="err">：</span>
</span></span><span class="line"><span class="cl">    <span class="n">string</span> <span class="n">m_name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// main 部分
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">Entity</span> <span class="nf">entity</span><span class="p">(</span><span class="s">&#34;aiken&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">entity</span><span class="p">.</span><span class="n">print</span><span class="p">()</span><span class="c1">// ....
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><code>std::move()</code>左右值转换</p>
<p><strong>参考资料：</strong> <a href="https://drewcampbell92.medium.com/understanding-move-semantics-and-perfect-forwarding-part-2-6b8266b6cfa4" target="_blank" rel="noopener">详细解析</a>
；<a href="https://www.cnblogs.com/sunchaothu/p/11392116.html" target="_blank" rel="noopener">Anthor one</a>
</p>
<h3 id="可选数据optional-datanew-in-c17">可选数据（Optional Data）（new in C++17）</h3>
<p>**基本设置：**项目，设置，C++，语言，c++语言标准&gt;17</p>
<p>针对那些我们<strong>可能会使用也可能不使用的可选数据</strong>。这也是一个c++ 17的内容：https://zh.cppreference.com/w/cpp/utility/optional</p>
<p>传统的就是通过引用传入一个bool flag，然后通过flag去判断是否存在之类的。但是有了optional我们就可以如下的方式去做</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;fstream&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;optional&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="n">std</span><span class="o">::</span><span class="n">optional</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span> <span class="n">readfile</span><span class="p">(</span><span class="n">cosnt</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">filepath</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">ifstream</span> <span class="n">stream</span><span class="p">(</span><span class="n">filepath</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(</span><span class="n">stream</span><span class="p">){</span><span class="k">return</span> <span class="n">string1</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">{};</span> <span class="c1">//这种写法其实是空tuple？还是要学一下的。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">data</span> <span class="o">=</span> <span class="n">readfile</span><span class="p">();</span> <span class="c1">//或者写那一长串optional string
</span></span></span><span class="line"><span class="cl"><span class="c1">//然后就可以使用
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">if</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="err">或者</span> <span class="k">if</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">have_value</span><span class="p">())</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>还有另一种使用方式就是，用于设定不存在数据的默认值。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">value</span> <span class="o">=</span> <span class="n">data</span><span class="p">.</span><span class="n">value_or</span><span class="p">(</span><span class="s">&#34;sdsds&#34;</span><span class="p">);</span> <span class="c1">//如果data是空的救会取到这个，相当于默认值把。
</span></span></span><span class="line"><span class="cl"><span class="c1">//比如
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">optional</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">count</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">c</span> <span class="o">=</span> <span class="n">count</span><span class="p">.</span><span class="n">value_or</span><span class="p">(</span><span class="mi">100</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="多类型变量multitype-variablenew-in-c-17">多类型变量（MultiType Variable）（new in C++ 17）</h3>
<p>换句话说就是数据的类型是在指定的范围内可选的，依托于<code>#include&lt;variant&gt;</code>通过指定数据可能的Type，然后用特殊的方式取出来。</p>
<p>它实际上存储的是所有类型的长度相加的空间；虽然能实现和unions类似的功能，但是实际上是更安全的。就是存储空间的占用更大？两者相比推荐这个把。</p>
<p><code>std::get_if</code>：对于这类型的数据很经常被拿来使用，我们可以参考<a href="https://zh.cppreference.com/w/cpp/utility/variant/get_if" target="_blank" rel="noopener">这里的</a>
用法</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">variant</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">,</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">data</span> <span class="o">=</span> <span class="s">&#34;Aiken&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 这种数值取出的方式只有在类型正确的时候才会起作用，不然会造成exception
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">get</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="o">&lt;&lt;</span><span class="s">&#34;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">data</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">get</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="o">&lt;&lt;</span><span class="s">&#34;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">----------------------------</span><span class="err">查看当前的数据类型</span><span class="o">-------------------------------</span>
</span></span><span class="line"><span class="cl"><span class="n">data</span><span class="p">.</span><span class="n">index</span><span class="p">();</span> <span class="c1">//这个index对应我们前面的定义的顺序
</span></span></span><span class="line"><span class="cl"><span class="c1">//另一种更优美的数据获取方式
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">auto</span><span class="o">*</span> <span class="n">value</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">get_if</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span><span class="p">(</span><span class="o">&amp;</span><span class="n">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// and we could use it like that 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">if</span><span class="p">(</span><span class="k">auto</span> <span class="n">value</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">get_if</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span><span class="p">(</span><span class="o">&amp;</span><span class="n">data</span><span class="p">))</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">    
</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>针对<strong>Get_if</strong>的具体实例可以写成这样：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;variant&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">variant</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="kt">float</span><span class="o">&gt;</span> <span class="n">v</span><span class="p">{</span><span class="mi">12</span><span class="p">};</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(</span><span class="k">auto</span> <span class="n">pval</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">get_if</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">(</span><span class="o">&amp;</span><span class="n">v</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">      <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;variant value: &#34;</span> <span class="o">&lt;&lt;</span> <span class="o">*</span><span class="n">pval</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl">    <span class="k">else</span> 
</span></span><span class="line"><span class="cl">      <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;failed to get value!&#34;</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>此外我们也可以通过这种类型来定义函数：这种的使用方式可以像这样看（对于可选的话，只是返回一个空值，这样可以更加具体的定义我们为什么访问不到文件），但是这种方式的话，不能用auto来代替吗</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="c1">//因为我们要当成类型传入，所以需要class但是这里不用return值吗
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">enum</span> <span class="k">class</span> <span class="nc">ErrorCode</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">None</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">NotFound</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">NoAccess</span> <span class="o">=</span><span class="mi">2</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span> <span class="n">variant</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">,</span><span class="n">ErrorCode</span><span class="o">&gt;</span> <span class="n">ReadFileAsString</span> <span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">{};</span> <span class="c1">//这里应该也是需要修改的把，改成ErrorCode类型
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="任意类型数据的存储store-any-typenew-in-c17">任意类型数据的存储（store any type）（new in C++17）</h3>
<p>我们也可以使用空指针来存储任意类型的数据；但是这不是这一块讨论的内容，这里讨论的是<code>std::any</code></p>
<p>就是一个能存储任意类型的variable，实际上和variant很像，但是那个更安全，因为我们知道所有的可能类型；同时这样的方式也会避免any可能会带来的动态内存分配，这个我们知道是相当影响性能的。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#include</span><span class="cpf">&lt;any&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="n">std</span><span class="o">::</span><span class="n">any</span> <span class="n">data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">data</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">data</span> <span class="o">=</span> <span class="s">&#34;aiken&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// variant 指定string的时候实际上会发生const char * 到string的隐式转换，但是any是不会的。
</span></span></span><span class="line"><span class="cl"><span class="c1">//any 取出变量的方式如下,在这种情况下数据类型不匹配的话，是不会成功取出的，我们还是需要知道我们当前的any type 以及按照指定的方式取出，所以实际上variant是一种更为安全的方式
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">string</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">any_cast</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span><span class="p">(</span><span class="n">data</span><span class="p">);</span> <span class="c1">//但是这样的话我们还是会有一个copy的操作，我们是否能够直接返回一种引用👇（别名）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">string</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">any_cast</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;&gt;</span><span class="p">(</span><span class="n">data</span><span class="p">);</span> 
</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>使用的情境：</strong></p>
<p>实际上是存储空间是有默认的小规模存储空间和大规模存储空间(限制);超过了小规模（32byte？）的情况下会使用动态的内存分配的机制。</p>
<p>当我们需要用any存储类似struct之类的大数据的时候，any可能就会调用new来动态的内存分配了。</p>
<p>能用variant就用，不行，导致非要用void*（空指针）的情况下就用any；但是最好的话，我们是不需要这种东西的。</p>
<p><strong>如何使用：</strong></p>
<h3 id="多维矩阵2darray">多维矩阵（2D+Array）</h3>
<p><strong>n维数组实际上就是n-1维数组的堆叠</strong>：array的array</p>
<p>也就是其实是<strong>指针</strong>机制：指针指向的地址存放一组指针，然后这组指针再指向各个Array，这就是2d array了。关键就是 <strong>指针的指针**</strong></p>
<p>多维矩阵第一次取出的时候实际上是指针类型，多重取出的最层才是数据。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 实际上就是用指针的指针的方式分配多维度的数组，更多维度也是一样的（星星更多了）。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kt">int</span><span class="o">*</span> <span class="n">array</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="p">[</span><span class="mi">50</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 分配50个存放int指针（int是返回的类型不是指针的类型）的空间
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kt">int</span><span class="o">**</span> <span class="n">a2d</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="o">*</span><span class="p">[</span><span class="mi">50</span><span class="p">];</span> <span class="c1">//绑定了50个内存位置
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="o">-------------------------------------------------------------------------------------</span>
</span></span><span class="line"><span class="cl">    <span class="c1">//实际的定义多维数组的方式,更高维度的就要嵌入更深的循环。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kt">int</span><span class="o">**</span> <span class="n">a2d</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="o">*</span><span class="p">[</span><span class="mi">50</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;</span><span class="mi">50</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">a2d</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="p">[</span><span class="mi">50</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>问题来到了下一步<strong>如何删除</strong>多维度的数组？</p>
<p>如果我们只delete最外层的指针，那么内部的所有指针地址，将会发生内存泄漏。</p>
<p>所以：我们需要像定义那样，反向的<strong>对每个指针都进行delete</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;</span><span class="mi">50</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">delete</span><span class="p">[]</span> <span class="n">a2d</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="k">delete</span><span class="p">[]</span> <span class="n">a2d</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这些50*k的存储空间实际上不一定是连续的，但可能是接近的，实际上是，再内存中随机的分配50个buffer来存放50个array，这种方式会越来越慢，（因为缓存的命中问题？），连续的存放可以使得缓存有更高的命中率来提升速度。</p>
<p>再某些情况使用1d array来代替2d array比如下（<strong>这不用看了，谁不会啊</strong>，手动换算行号呗），但是这样的代码在<strong>执行的时候，快很多</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">int</span><span class="o">*</span> <span class="n">array</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="p">[</span><span class="mi">5</span><span class="o">*</span><span class="mi">5</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="c1">//我还以为，是类似的写法也可以，这样的话，谁不会啊。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">y</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="n">y</span><span class="o">&lt;</span><span class="mi">5</span><span class="p">;</span><span class="n">y</span><span class="o">++</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="n">x</span><span class="o">&lt;</span><span class="mi">5</span><span class="p">;</span><span class="n">x</span><span class="o">++</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">array</span><span class="p">[</span><span class="n">x</span> <span class="o">+</span> <span class="n">y</span><span class="o">*</span><span class="mi">5</span><span class="p">]</span> <span class="o">=</span><span class="mi">2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="隐式转换和显式转换implicit-conversion-and-the-explicit-keyword">隐式转换和显式转换（Implicit Conversion and the Explicit Keyword）</h3>
<p>隐式转换和显式关键词</p>
<p><strong>隐式：不用告诉他他究竟要做什么</strong></p>
<p>很多时候由于类的构造函数实现，基于类的输入类型，我们可以将函数表示的初始化，转化为等号的。同时也能在一些特定的场景下执行内置的类型转换。</p>
<p>但是如果是我的话，我尽量不会这么去做🔜，因为这样会增加阅读的负担。</p>
<p><strong>显式关键词：不让执行隐式转换</strong></p>
<p><code>Explicit</code> 加在构造函数的最前方，这就是让构造函数只能被显式调用，不能执行隐式调用。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="cp">#include&lt;iostream&gt;
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="k">using</span> <span class="n">String</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Entity</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">String</span> <span class="n">m_name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">m_age</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">Entity</span><span class="p">(</span><span class="k">const</span> <span class="n">String</span><span class="o">&amp;</span> <span class="n">name</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="o">:</span><span class="n">m_name</span><span class="p">(</span><span class="n">name</span><span class="p">){}</span>
</span></span><span class="line"><span class="cl">    <span class="n">Entity</span><span class="p">(</span><span class="kt">int</span> <span class="n">age</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="o">:</span><span class="n">m_age</span><span class="p">(</span><span class="n">age</span><span class="p">){}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">PrintEntity</span><span class="p">(</span><span class="k">const</span> <span class="n">String</span><span class="o">&amp;</span> <span class="n">name</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// print
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 在这一步中C++将根据构造函数进行隐式转换，前提是对应的类别要是正确的
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">Entity</span> <span class="n">a</span> <span class="o">=</span> <span class="mi">22</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">Entity</span> <span class="n">b</span> <span class="o">=</span> <span class="n">String</span><span class="p">(</span><span class="s">&#34;aiken&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 第二种自动进行隐式转换的场景，实际上和上面是完全一致的
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">printEntity</span><span class="p">(</span><span class="n">String</span><span class="p">(</span><span class="err">&#39;</span><span class="n">asdad</span><span class="err">&#39;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">cin</span><span class="p">.</span><span class="n">get</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>cast：类型转换从typeA-&gt; type B</p>
<ul>
<li>int（22）之类的</li>
<li>所有的类名也能这么做（借助隐式调用这样的）</li>
</ul>
<h3 id="类型转换type-casting">类型转换（Type Casting）</h3>
<p>cast实际上会为我们检查类型是否正确等等</p>
<p><strong>显式转换：<strong>显式的</strong>指定</strong>我们希望将当前类型<strong>强制转换</strong>成什么<strong>目标类型</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">double</span> <span class="n">s</span> <span class="o">=</span> <span class="k">static_cast</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">(</span><span class="n">value</span><span class="p">)</span><span class="o">+</span> <span class="mf">5.3</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>**隐式转换：**不需要我们显式的指定转换的数据类型，根据输入输出会自动转换</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="c1">// 反过来也是可以的
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kt">double</span> <span class="n">value</span> <span class="o">=</span> <span class="mf">5.25</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl"><span class="c1">// 我们同样也可以显式的指定,但是这种转换不是强制的，只是显式的表达
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kt">double</span> <span class="n">b</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">value</span><span class="p">;</span><span class="c1">//safe style csat的样式
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kt">double</span> <span class="n">b</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">value</span> <span class="o">+</span><span class="mf">5.2</span> <span class="c1">//我们可以看看没有这个int的结果
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>实际上存在四种不同的Casting：<code>static_cast</code>，<code>const_cast</code>，<code>dynamic_cast</code>，<code>reinterpret_cast</code> ，这几种cast的使用请 <a href="https://zh.cppreference.com/mwiki/index.php?title=Special%3A%E6%90%9C%E7%B4%A2&amp;search=cast&amp;button=" target="_blank" rel="noopener">GoogleIt</a>
来补充基本的含义，以及一些使用情况，（CPP reference是真的牛逼）</p>
<p>在一些情况下转换失败的话会return null，所以也可以用做派生类的检查。</p>
<p><strong>const</strong>：用来从const到非const</p>
<p><strong>dynamic</strong>：用于从基类到子类的指针转换，（反过来可以，但是实际上不需要显式转换）</p>
<blockquote>
<p>其实是一种function，实际上会有一些额外的操作。</p>
<p>如果这个转换是错误的，那么这个指针会返回null，所以实际上，这个指针可以用作类型之间继承关系的验证作用。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="c1">// 基本定义
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">class</span> <span class="nc">Entity</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Player</span> <span class="o">:</span> <span class="k">public</span> <span class="n">Entity</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Enemy</span> <span class="o">:</span> <span class="k">public</span> <span class="n">Entity</span><span class="p">{};</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>实际上由于存储了运行的中间状态（runtime type infomation默认是启用的，关闭会报错），所以是可以知道该类到底是啥的，也就是支持从基类推导到该子类到底是啥。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">Player</span><span class="o">*</span> <span class="n">player</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Player</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="n">Entity</span><span class="o">*</span> <span class="n">e</span> <span class="o">=</span> <span class="n">player</span><span class="p">;</span> <span class="c1">//毫无问题
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">Entity</span><span class="o">*</span> <span class="n">e1</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Enemy</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">Player</span><span class="o">*</span> <span class="n">p0</span> <span class="o">=</span> <span class="k">dynamic_cast</span><span class="o">&lt;</span><span class="n">Player</span><span class="o">&gt;</span><span class="p">(</span><span class="n">e1</span><span class="p">);</span> <span class="c1">//这种转换不可行，会return null
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">Player</span><span class="o">*</span> <span class="n">p1</span> <span class="o">=</span> <span class="k">dynamic_cast</span><span class="o">&lt;</span><span class="n">Player</span><span class="o">&gt;</span><span class="p">(</span><span class="n">e</span><span class="p">);</span> <span class="c1">//从基类转换到子类 ok，但是这种情况下我们需要指定多态，也就是virtual 为了避免冲突，这其实是一个多态的用法
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">if</span><span class="p">(</span><span class="k">dynamic_cast</span><span class="o">&lt;</span><span class="n">Player</span><span class="o">&gt;</span><span class="p">(</span><span class="n">e1</span><span class="p">)){}</span> <span class="c1">//验证类型的用法
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></blockquote>
<p><strong>reinterpret</strong>:用于无关类型的转换，还是需要再搜索一下，不太常用，推荐的可以使用的情况，类型转换转换回原本类型的时候</p>
<p>这种类型转换实际上是更可靠的。</p>
<h3 id="类型双关type-punning">类型双关（Type Punning）</h3>
<p><strong>实际上就是获取某种类型变量的指针，然后转化成另一种类型的指针的操作。</strong></p>
<p><a href="http://tisyang.is-programmer.com/posts/38184" target="_blank" rel="noopener">Google it</a>
</p>
<p>当然接下来我们也可以解引用,其他之类的。</p>
<p>首先看一串示例代码（double）实际上是为了让到double的隐式转换更加清晰，并没有真正的操作指令。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="c1">// 这样的操作实际上就是a-b的隐式转换，但是这样的话，内存空间实际上是没有公用的，b是用的另外赋值的双精度的5
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">double</span> <span class="n">b</span> <span class="o">=</span> <span class="p">(</span><span class="kt">double</span><span class="p">)</span><span class="n">a</span><span class="p">;</span> 
</span></span><span class="line"><span class="cl"><span class="c1">// 反过来也是一样的道理
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果我们想要直接使用指针转换，将double指针转换到int指向的内存地址，这样的话，由于<strong>两种类型的长度不同</strong>，所以会导致输出<strong>错</strong>，严重的话还会导致<strong>崩溃</strong>。</p>
<p>但是实际上，这样的操作，我们可以通过同样长度的内存操作，来直接的对内存进行操作，但是正常人没有人这么干。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">Entity</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span><span class="o">*</span> <span class="nf">GetPositions</span><span class="p">(){</span><span class="k">return</span> <span class="o">&amp;</span><span class="n">x</span><span class="p">;}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">Entity</span> <span class="n">e</span> <span class="o">=</span> <span class="p">{</span><span class="mi">5</span><span class="p">,</span><span class="mi">8</span><span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span><span class="o">*</span> <span class="n">position</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span><span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">e</span><span class="p">;</span> <span class="c1">//将struct的指针转化为int指针
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">postition</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">&lt;&lt;</span><span class="n">postirion</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">&lt;&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">y</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span><span class="p">)((</span><span class="kt">char</span><span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">e</span><span class="o">+</span><span class="mi">4</span><span class="p">);</span> <span class="c1">// 通过char的单字节操作获取到第二个指针的地址。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kt">int</span><span class="o">*</span> <span class="n">z</span> <span class="o">=</span> <span class="n">e</span><span class="p">.</span><span class="n">Getpositions</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="part-3-poniter--references指针与引用">Part 3 Poniter &amp; References指针与引用</h2>
<p>从指针的含义出发，对各种不同指针的用法，引用场景，内在含义，进行分析，记录世界记录你。永远的神，指针。</p>
<p><strong>指针</strong>实际上就是一个1byte的<strong>整型值</strong>，<strong>它就是一个地址</strong>，指示你在内存中存储该值的位置，和类型没有半毛钱关系，类型只是指示你可能放了个啥类型的数据在那个地址<code>Void* ptr = &amp;var;</code></p>
<p><strong>引用</strong>和指针本质上是一回事，用法上会有所区别它实际上是基于指针的一种高级修饰，是对某个已经存在的var的引用。他并不是一个真正的变量。<code>Int&amp; ref = var。</code></p>
<blockquote>
<p>引用能做的指针都能做，实际上是一种代码的优化和简化过程（moew clean），主要的用处就在将var而不是value传入function（达到能够直接修改var的作用）</p>
</blockquote>
<h3 id="指针基础pointer">指针基础（pointer）</h3>
<p><strong>-&gt;的访问方式</strong>：实际上等同于(*e1).method，<code>Arrow-&gt;</code>只能在左边是指针的时候使用，而<code>.</code>调用的方式左边只能是实体。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">Entity_virtual</span> <span class="n">e1</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Entity_virtual</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">e1</span><span class="o">-&gt;</span><span class="n">GetName</span><span class="p">()</span><span class="o">&lt;&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">Entity_virtual</span> <span class="nf">e2</span><span class="p">(</span><span class="s">&#34;Aiken2&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">e2</span><span class="p">.</span><span class="n">GetName</span><span class="p">()</span><span class="o">&lt;&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>基本的定义和使用方式：</strong></p>
<ul>
<li><u>用<code>*</code>定义一个指针类型（用来存放地址）= &amp;var（用该符号取出后接变量存储所在的内存地址）var</u>
<ul>
<li>然后我们可以在Debug Stage从windows的memory找到该变量在内存中的值。</li>
<li><strong>实际上也可以用</strong><code>type* name = Value</code>，这样的话name还是指的是value所在的地址。但是这种时候type就需要写好了。</li>
</ul>
</li>
<li>在指针类型变量前加*表示我们<strong>访问</strong>该地址所存储的Var，我们可以对该var进行读取写入或者修改，但是在这个时候，我们写入的值就和之前所提到的类型有关了（指针本身是无关的）
<ul>
<li>因为<strong>类型会告诉内存，我们写入的数据要在内存中占用多少个字节</strong>，多少位之类的信息，而如果我们使用void，那当我们给该指针取到的数据赋值的时候，compiler就不知道怎么存储该数据，也就会导致error。</li>
</ul>
</li>
<li>也可以用<code>**</code>定义<u>指针的指针</u>，也就是指针所在的内存空间的地址
<ul>
<li>BTW:从内存窗口看到的地址是逆序的</li>
</ul>
</li>
<li>可以将指针定义为nullptr，后续再赋值，而引用必须马上引用一个已经存在的变量，他不是一个新的变量。</li>
<li>在<u>同一行里定义多个指针变量</u>的时候要在<strong>每一个前面+</strong><code>*</code>千万别忘了</li>
</ul>
<p><strong>注意事项：</strong></p>
<ol>
<li>++之类的运算符号的<strong>优先级</strong>&gt; *取值，所以我们要<strong>加入括号</strong>，使其首先解引用，防止改变的是地址的值而不是value。</li>
<li>“0”不是一个有效的内存地址</li>
<li><strong>指针偏移值</strong>实际上取决于指针前面的type：如下图就是加入了两个int长度的地址。</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">example</span><span class="p">[</span><span class="mi">5</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span><span class="o">*</span> <span class="n">ptr</span> <span class="o">=</span> <span class="n">example</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="mi">5</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">example</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span><span class="mi">2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">example</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">*</span><span class="p">(</span><span class="n">ptr</span><span class="o">+</span><span class="mi">2</span><span class="p">)</span><span class="o">=</span><span class="mi">6</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">//上述也等同于
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="o">*</span><span class="p">((</span><span class="kt">char</span><span class="o">*</span><span class="p">)</span><span class="n">ptr</span> <span class="o">+</span> <span class="mi">8</span><span class="p">)</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="引用基础references">引用基础（references）</h3>
<ul>
<li>
<p>用<code>type&amp; ref = var</code>定义一个对var的引用，不需要其他的操作符</p>
</li>
<li>
<ul>
<li>实际上ref就是一个别称，他<strong>不是实际存在</strong>的，只是var的另一种表达形式。</li>
<li>需要立即赋值。</li>
</ul>
</li>
<li>
<p>具体的用途除了<strong>创建别名</strong>方便读写以外：主要用于需要修改原值的参数引用定义上。</p>
</li>
<li>
<ul>
<li>
<p>function中通常情况下，是传值，而不是传递变量的地址。所以会有额外的内存拷贝的操作发生；所以通过function中的value产生的变化实际上是不会影响传入的变量的，这时候我们需要使用引用将<strong>变量传入</strong>，<strong>而不是值传入</strong>。（if we need this operation，也就是我们需要影响原值的时候）那么实现的方法有下面的三种。</p>
</li>
<li>
<ol>
<li>
<p>要这么做的话实际上就是，我们将内存地址传入，然后通过地址取值进行操作，而不是只将这个值copy一下传进去也就是<code>def fun(int* var)</code>; <code>func(&amp;var)</code>;当然这种方式也适用于<strong>直接传入指针</strong>，</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">def</span> <span class="nf">fun</span><span class="p">(</span><span class="kt">int</span><span class="o">*</span> <span class="n">var</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">func</span><span class="p">(</span><span class="o">&amp;</span><span class="n">var</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>对1进行修正，更优雅的写法，简洁，就是使用reference，接受传入的是别名，也就是具体的变量，而不是值。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">def</span> <span class="nf">func</span><span class="p">(</span><span class="n">type</span><span class="o">&amp;</span> <span class="n">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">func</span><span class="p">(</span><span class="n">var</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>当然我们也可以通过return来改变原值，但是这样会需要temp value来影响内存效率之类的东西，也比较傻逼。</p>
</li>
</ol>
</li>
</ul>
</li>
<li>
<p>无法改变引用的对象。</p>
</li>
<li>
<p>再func前面类型定义为<code>Type&amp;</code>,那么我们正常的<code>return</code>就是返回一个<u>原值的引用</u>。</p>
</li>
</ul>
<h3 id="指针的-操作符arrow-operator-">指针的-&gt;操作符(Arrow Operator )</h3>
<p><strong>→用来取代解引用后取值，就是用于指针直接调用参数或者函数，免去用<code>*</code>解引用的过程</strong>。</p>
<ul>
<li>
<p>但是所有的操作符都可以重载，我们可以在自己的类别中定义他：比如当我们用一个Class     装载别的Class的指针的时候（比如我们为了让他能自己delete），如果我们希望能够直接指向最底层的那个Class 的function的时候。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="c1">// ScopedPtr存放另一个class（Entity）的指针，和构造析构函数。
</span></span></span><span class="line"><span class="cl"><span class="c1">// 重载使得直接调用底层类别中的函数。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">Entity</span><span class="o">*</span> <span class="k">operator</span><span class="o">-&gt;</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">m_obj</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">ScopedPtr</span> <span class="n">entity</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Entity</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="n">entity</span><span class="o">-&gt;</span><span class="n">Print</span><span class="p">();</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>获取类中参数的内存偏移量（可能是特殊的用法把，和第一点最基础的代码完全不一样）：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">Vector3</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">float</span> <span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">,</span><span class="n">z</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">offset</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="o">&amp;</span><span class="p">((</span><span class="n">Vector3</span><span class="o">*</span><span class="p">)</span><span class="k">nullptr</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">x</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">count</span> <span class="o">&lt;&lt;</span> <span class="n">offset</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// x,y,z会分别Get到0，4，8（字节）
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
</ul>
<h3 id="函数指针function-pointer">函数指针（Function Pointer）</h3>
<p>主要目的就是：获取函数所在的内存空间的地址；</p>
<p><a href="https://zh.cppreference.com/w/cpp/language/pointer" target="_blank" rel="noopener">https://zh.cppreference.com/w/cpp/language/pointer</a>
</p>
<p>函数指针的补充资料：<a href="https://blog.csdn.net/zj1131190425/article/details/92065897" target="_blank" rel="noopener">link1</a>
，<a href="https://zhuanlan.zhihu.com/p/37306637" target="_blank" rel="noopener">Link2</a>
，还需要通过编程来加深理解</p>
<p>实际上应该还有其他类型的表达；</p>
<p><strong>定义和使用</strong></p>
<p>记住这里1不加括号（有参数输入的时候才加入括号），这就等同于在HW卡面+&amp;</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">function</span> <span class="o">=</span> <span class="n">HelloWorld</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">//记住这里不加括号（有参数输入的时候才加入括号），这就等同于在HW卡面+&amp;
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>下面这种定义方式便于我们理解：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="c1">//等于下面这种方式
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kt">void</span><span class="p">(</span><span class="o">*</span><span class="n">cherno</span><span class="p">)()</span> <span class="o">=</span> <span class="n">HelloWorld</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">cherno</span><span class="p">();</span> <span class="c1">// 调用函数。
</span></span></span><span class="line"><span class="cl"><span class="c1">// 通过4-5的参数对比，我们可以知道cherno就是一个函数的别名。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// 这种方式其实更规范的可以写成 :这里添加了参数的输入所以比较不一样
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">typedef</span> <span class="nf">void</span><span class="p">(</span><span class="o">*</span><span class="n">HelloWorldFunction</span><span class="p">)(</span><span class="kt">int</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">HelloWorldFunction</span> <span class="n">function</span> <span class="o">=</span> <span class="n">HelloWorld</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">function</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>函数指针的使用场景：</strong></p>
<p>主要用于把function传入function，和lambda匿名函数好像有比较好的结合</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">PrintValue</span><span class="p">(</span><span class="kt">int</span> <span class="n">value</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">//Print cout
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">ForEach</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">values</span><span class="p">,</span> <span class="kt">void</span><span class="p">(</span><span class="o">*</span><span class="n">func</span><span class="p">)(</span><span class="kt">int</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="nl">value</span> <span class="p">:</span> <span class="n">values</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">func</span><span class="p">(</span><span class="n">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">values</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="n">ForEach</span><span class="p">(</span><span class="n">values</span><span class="p">,</span> <span class="n">PrintValue</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="智能指针smart-pointer">智能指针（Smart Pointer）</h3>
<p><strong>非常重要，能用智能指针的情况下我们就不用传统的指针</strong></p>
<p>作用域:{}  <a href="https://blog.csdn.net/xuyouqiang1987/article/details/104127669" target="_blank" rel="noopener">参考资料1</a>
；<a href="https://blog.csdn.net/shaosunrise/article/details/85158249" target="_blank" rel="noopener">参考资料2</a>
</p>
<p><strong>唯一指针</strong>，能够自动的在作用域外就进行销毁（最基本的智能指针）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="cp">#include&lt;memory&gt;
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="c1">// 下面这个是错误的，给个范例
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">unique_ptr</span><span class="o">&lt;</span><span class="n">Entity</span><span class="o">&gt;</span> <span class="n">entity</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Entity</span><span class="p">();</span>  <span class="c1">// 这个是错误的！！！！！！！
</span></span></span><span class="line"><span class="cl"><span class="c1">//只能显式调用构造函数：正确↓
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">unique_ptr</span><span class="o">&lt;</span><span class="n">Entity</span><span class="o">&gt;</span> <span class="n">entity</span><span class="p">(</span><span class="k">new</span> <span class="n">Entity</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"><span class="c1">//另一种 写法：推荐写法：最好就这么写
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">unique_ptr</span><span class="o">&lt;</span><span class="n">Entity</span><span class="o">&gt;</span> <span class="n">entity</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">make_unique</span><span class="o">&lt;</span><span class="n">Entity</span><span class="o">&gt;</span><span class="p">();</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>共享指针</strong>，<u>另一种智能指针</u>，</p>
<p>使用reference_count来进行引用指针的计数，对象的所有引用消除了以后（count=0），才进行销毁（delete）</p>
<p>主要功能：</p>
<p>管理动态创建的对象的销毁。它的基本原理就是记录对象被引用的次数，当引用次数为 0 的时候，也就是最后一个指向某对象的<strong>共享指针析构</strong>的时候，共享指针的析构函数就把<strong>指向的内存区域</strong>释放掉。就是一个对象可以有多个引用。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">share_ptr</span><span class="o">&lt;</span><span class="n">Entity</span><span class="o">&gt;</span> <span class="n">sharedEntity</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">make_shared</span><span class="o">&lt;</span><span class="n">Entity</span><span class="o">&gt;</span><span class="p">();</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>弱指针</strong>weak_ptr: 是一种弱化的共享指针，不会进行reference count</p>
<p><a href="https://blog.csdn.net/albertsh/article/details/82286999" target="_blank" rel="noopener">https://blog.csdn.net/albertsh/article/details/82286999</a>
</p>
<p>它不会等到全部的指针都被销毁了才销毁，它会在指针销毁的时候就对对象进行析构，所以可能会有部分指针指向没有分配值的地址。</p>
<hr>
<p>**总结一下：**重要！！！</p>
<ul>
<li>所以只是当我们需要在一个<strong>heap</strong>上声明的对象，但是希望能在作用域外自动销毁的时候我们才应该使用智能指针。</li>
<li>也就是智能指针分配的数据空间是在heap上的，但是存储指针自身的空间是在stack上的</li>
<li>先思考使用unique point 在需要不同的地方共享的时候在考虑share pointer
<ul>
<li>避免使用<code>new</code> <code>delete</code></li>
</ul>
</li>
<li>实际上智智能指针就是对原生指针的一个高层封装，就是类似struct ，在struct 的destructor 调用指针指向地址的delete？ 看看视频中的代码。</li>
</ul>
<h2 id="part-4-class--struct-面向对象">Part 4 Class &amp; Struct 面向对象</h2>
<p>This Chapter 主要就是<u>面向对象的编程逻辑</u>，以及类和结构体中的一些知识点</p>
<p><strong>面向对象编程</strong>：这是一种非常流行的编程思想，这是一种编码的风格。</p>
<p>jave所有的一切都应该是一个class.</p>
<h3 id="类class">类（Class）</h3>
<p><strong>Class</strong>：和python是一样的，是一种将<strong>数据</strong>和<strong>function</strong>（<strong>method</strong>）组织在一起的一种方式。</p>
<p>和namespace的区别是啥：namespace没有访问控制。</p>
<h4 id="一些基础用法和信息">一些基础用法和信息</h4>
<ol>
<li>
<p>比如玩家的属性，和玩家的一些function，就可以使用class的instance来定义多个角色，而不必重复的定义类似的方法和属性值。</p>
</li>
<li>
<p>类中的function就被称为method</p>
</li>
<li>
<p>可以使用大括号的方式来初始化赋值</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">Vector2</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">float</span> <span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">Vector2</span> <span class="n">a</span> <span class="o">=</span> <span class="p">{</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>实际上可以在类内declaration函数，然后再类外用::namespace的方式进行定义</p>
</li>
<li>
<p>当我们想要将Class or Struct传入Function中的时候，我们最好是使用reference <code>&amp;</code>和<code>Const</code>，这样可以防止传入的类之类的被修改，同时也节省了memory，不需要额外的生成一个copy。</p>
</li>
<li>
<p>建立一个Logging类：将warning Or Error 打印在控制台上，因为控制台永远不会出问题，对于debug很有帮助。</p>
</li>
<li>
<p>继承所有在Entity中不是private的都会被player继承。</p>
</li>
</ol>
<h4 id="访问控制visibility">访问控制（Visibility）</h4>
<ul>
<li>public：可以在类外访问，也就是可以在类的外部随便定义，取出，或者修改。</li>
<li>private：只能通过类内的操作或者类内的函数，以及friends进行修改调用。</li>
<li>protect：类内或者继承类</li>
</ul>
<p>friend的定义方式：在类内的public使用前置<code>friend</code> 去重载这个函数或者类别即可。就能访问私有变量了。</p>
<h4 id="类的构造函数和析构函数">类的构造函数和析构函数</h4>
<p><a href="https://www.runoob.com/cplusplus/cpp-constructor-destructor.html" target="_blank" rel="noopener">C++ 类构造函数 &amp; 析构函数 | 菜鸟教程 (runoob.com)</a>
</p>
<p><strong>constructors</strong>**：构造函数（可重载）**</p>
<ul>
<li>
<p>用于每个instance生成时候的初始化，我们可以通过不同的传入值来<strong>重载</strong>这个函数。</p>
</li>
<li>
<p>名称和类名一致，不需要type。</p>
</li>
<li>
<p>默认是存在constructor的（但是不初始化变量），如果我们不希望用户构建实例，我们可以将constructor写在private中，那么就无法使用该类别去生成一个实例。</p>
</li>
<li>
<p>函数构造的<strong>初始化列表</strong>：</p>
<p>构造函数初始化列表以一个<strong>冒号开始</strong>，接着是以<strong>逗号分隔</strong>的数据成员列表，每个数据成员后面跟一个放在括号中的初始化式。</p>
<p>但是这种方式，需要我们按照成员函数的<strong>顺序去编写</strong>，他是默认这样执行的。</p>
<p><a href="https://www.runoob.com/w3cnote/cpp-construct-function-initial-list.html" target="_blank" rel="noopener">类构造函数初始化列表</a>
。</p>
<ul>
<li>这样假如我们成员中有类别实体，我们可以避免该类别实体进行重复的构造，浪费了性能。（可以用cout测试）</li>
<li>此外这样也可以分离初始化参数和一些其他的初始化指令操作（写在大括号里）。</li>
</ul>
</li>
</ul>
<p><strong>Destructor</strong>**：析构函数**</p>
<p>用于destory我们生成的object或者说instance；清除变量。</p>
<ul>
<li>在构造函数前面加~就是定义的方式。一般不需要显式编程</li>
<li>活到生命周期末尾（大括号之类的）会自动调用</li>
<li>如果New 就需要Delete才会调用</li>
</ul>
<h4 id="类的继承">类的继承</h4>
<p>继承的主要作用，是让我们拒绝duplicated，拒绝代码重复。所以我们就能在父类中放置通用功能，然后在子类中重载或者编写新功能。</p>
<ul>
<li>在子类的定义的时候<code>：[public] 父类，父类2</code></li>
<li>如果函数的输入是（<code>父类* a</code>），那么所有的子类都可以输入来着 ：实际上是多态的因素，就是所有的子类都属于父类把，所以父类的指针可以代表所有的子类。</li>
</ul>
<p><strong>虚函数Virtual Function</strong></p>
<ol>
<li>
<p>在父类中编写的<strong>virtual function</strong>就能在子类中选择覆盖重载</p>
</li>
<li>
<p><strong>Virtual   function</strong>可以避免在特殊情况下，我们在子类覆盖定义了父类函数的情况下，还是调用了夫类中的同名函数的情况：它加入了动态分配的机制，通过存档虚函数 所代表的各种虚函数映射情况，便于我们<strong>找到正确的函数</strong>。</p>
</li>
<li>
<p>实际上也就是在<strong>需要重载（override）函数</strong>前面加入一个<strong>virtual</strong>的关键字（在最前面）；同时可以在覆写（override）的地方加上<strong>override</strong>关键字（在声明的最后面，大括号的前面），但是这不是必须的，但是更具备可读性。</p>
</li>
<li>
<p>但是需要额外的内存空间：需要表需要基类指向虚函数表的指针；</p>
</li>
<li>
<p>需要额外的运行速度：因为每次调用虚函数，需要额外遍历虚函数；</p>
</li>
<li>
<p>一般情况损耗不会太大，除非对于嵌入式设备来说。</p>
</li>
</ol>
<p><strong>Virtual Destructors</strong></p>
<p>和virtual一样，为了我们在使用子类进行多态操作的时候，不会发生没有调用destructor导致内存泄漏的情况。所以就要再析构函数的时候virtual一下。</p>
<p><strong>Interface（PureVirtualFunction）纯虚函数</strong></p>
<p>纯虚函数也可以理解为接口，就是需要后续被实现的一些</p>
<ul>
<li>实际纯虚函数就是一种在基类中没有实现的函数：在Jave和C#这类语言中就被称作接口，也就是我们需要在子类中一定要重写的函数。（有时候我们需要每个子类都定义特殊的函数，基类的定义顶多就当作模板，不包含实现方法）</li>
<li>在基类中对虚函数的实现（<code>{}</code>）改成（<code>=0；</code>），就是纯虚函数了，如果我们想要使得子类能够实例化对象，我们就必须在子类中override这个纯虚函数。这种时候基类也不能被实例化了。</li>
<li>如果父类对祖父类的override了，那么我们可以直接继承父类就不用再覆写了。BTW：纯虚函数（和成员变量）组成的也叫做抽象类</li>
</ul>
<h4 id="类的多态">类的多态</h4>
<p>多态 <a href="https://www.runoob.com/cplusplus/cpp-polymorphism.html" target="_blank" rel="noopener">https://www.runoob.com/cplusplus/cpp-polymorphism.html</a>
</p>
<p>其实就是用base的指针来指向子类的一种调用方式</p>
<h3 id="this-指针">“This” 指针</h3>
<p>this是指指向当前对象的指针，索引到当前的instance；</p>
<p>用来调用当前类中的函数或者变量</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Entity</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">	<span class="kt">int</span> <span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="n">Entity</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="kt">int</span> <span class="n">y</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="k">this</span><span class="p">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">x</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="复制构造函数以及浅拷贝深拷贝">复制构造函数以及浅拷贝深拷贝</h3>
<h4 id="基本概念">基本概念</h4>
<p>通常对Class进行复制或者等号赋值操作的时候，很多情况下会发生内存拷贝，这样会使用新的内存地址去存储新的相同数据，也就是建立一个副本，但是很多情况下是不需要的。（<strong>用等号的时候都是进行的copy</strong>）</p>
<p>这种方式就是建立副本：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">Vector2</span> <span class="n">a</span> <span class="o">=</span> <span class="p">{</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="n">Vector2</span> <span class="n">b</span> <span class="o">=</span> <span class="n">a</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">b</span><span class="p">.</span><span class="n">x</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span> <span class="c1">//不改变a
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以使用指针建立指针的副本，数据空间不进行拷贝；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">Vector2</span><span class="o">*</span> <span class="n">a</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Vector2</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="n">Vector2</span><span class="o">*</span> <span class="n">b</span> <span class="o">=</span> <span class="n">a</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">b</span><span class="o">-&gt;</span><span class="n">x</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="浅拷贝以自定义的string为例">浅拷贝：以自定义的String为例</h4>
<p>c++已经实现了，这就是个范例；</p>
<p><strong>memcpy</strong>是内存赋值（赋值内存块）：在这里就是取代for loop 去copy value</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">String</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">	<span class="kt">char</span><span class="o">*</span> <span class="n">m_buffer</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">m_size</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">	<span class="n">String</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">string</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="n">m_size</span> <span class="o">=</span> <span class="n">strlen</span><span class="p">(</span><span class="n">string</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="n">m_buffer</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">char</span><span class="p">[</span><span class="n">m_size</span> <span class="o">+</span> <span class="mi">1</span><span class="p">];</span> <span class="c1">//假设包含终止符的情况，但是这样就会对于非普通string的类别不太安全（它们可能不包括终止符）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="n">memcpy</span><span class="p">(</span><span class="n">m_buffer</span><span class="p">,</span> <span class="n">string</span><span class="p">,</span> <span class="n">m_size</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="k">friend</span> <span class="n">std</span><span class="o">::</span><span class="n">ostream</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">&lt;&lt;</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">ostream</span><span class="o">&amp;</span> <span class="n">stream</span><span class="p">,</span> <span class="k">const</span> <span class="n">String</span><span class="o">&amp;</span> <span class="n">string</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">ostream</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">&lt;&lt;</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">ostream</span><span class="o">&amp;</span> <span class="n">stream</span><span class="p">,</span> <span class="k">const</span> <span class="n">String</span><span class="o">&amp;</span> <span class="n">string</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="n">stream</span><span class="o">&lt;&lt;</span> <span class="n">string</span><span class="p">.</span><span class="n">m_buffer</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="n">stream</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>基于终止符的不同情况，我们可以修改成：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">memcpy</span><span class="p">(</span><span class="n">m_buffer</span><span class="p">,</span> <span class="n">string</span><span class="p">,</span> <span class="n">m_size</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">m_buffer</span><span class="p">[</span><span class="n">m_size</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>但是实际上这样可能会发生内存泄漏，所以实际上我们不应该忘记析构函数：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="o">~</span><span class="n">String</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">delete</span><span class="p">[]</span> <span class="n">m_buffer</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>但是如果我们在这种情况下定义的string进行复制的时候，我们会发现，我们实际上是对类中所有的value进行copy，所以我们实际上拷贝了一个指针，然后再最终程序结束的时候，我们对同一个地址调用了两次析构函数，于是程序崩溃了。这就是<strong>浅拷贝</strong>。</p>
<h4 id="深拷贝以自定义的string为例">深拷贝：以自定义的String为例</h4>
<p>我们想要的就是有一个指向新地址的新指针，然后指向的地址有一样的value。</p>
<p>于是<strong>复制构造函数</strong>就被需要了，就是实际上我们是重新调用了一次前面的构造函数，去构造了一个完全相同的变量，而不是只是浅拷贝。</p>
<p><u><em>C++实际上已经存在了一个默认了：我们可以直接声明，但是这实际上是浅拷贝，也就是默认的方式</em></u></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">String</span><span class="p">(</span><span class="k">const</span> <span class="n">String</span><span class="o">&amp;</span> <span class="n">other</span><span class="p">);</span> <span class="c1">//这个实际上是浅拷贝 == 下面的
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="n">String</span><span class="p">(</span><span class="k">const</span> <span class="n">String</span><span class="o">&amp;</span> <span class="n">other</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">:</span><span class="n">m_buffer</span><span class="p">(</span><span class="n">other</span><span class="p">.</span><span class="n">m_buffer</span><span class="p">),</span> <span class="n">m_size</span><span class="p">(</span><span class="n">other</span><span class="p">.</span><span class="n">m_size</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">or</span> <span class="k">if</span> <span class="n">you</span> <span class="n">want</span> <span class="n">to</span> <span class="n">be</span> <span class="n">more</span> <span class="n">exciting</span><span class="p">...</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 也等同于下面这个，都是浅拷贝
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">String</span><span class="p">(</span><span class="k">const</span> <span class="n">String</span><span class="o">&amp;</span> <span class="n">other</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">memcpy</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">other</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">String</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>那么如果我们想要完全禁用浅拷贝：我们可以在声明后面加上=delete</p>
<p>实际上就是通过构造函数的类型隐式转换（就是那个等号的重载来实现的），所以我们要弄一个<strong>深拷贝</strong>的话：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">String</span><span class="p">(</span><span class="k">const</span> <span class="n">String</span><span class="o">&amp;</span> <span class="n">other</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">:</span><span class="n">m_size</span><span class="p">(</span><span class="n">other</span><span class="p">.</span><span class="n">m_size</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="n">m_buffer</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">char</span><span class="p">[</span><span class="n">m_size</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="n">memcpy</span><span class="p">(</span><span class="n">m_buffer</span><span class="p">,</span> <span class="n">other</span><span class="p">.</span><span class="n">m_buffer</span><span class="p">,</span> <span class="n">m_size</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="单例singleton">单例（singleton）</h3>
<p><a href="https://blog.csdn.net/hit0803107/article/details/54411180" target="_blank" rel="noopener">单例模式(Singleton)及其C++实现_FBeetle的博客-CSDN博客</a>
</p>
<p>单例是面向对象里面的一种编程模式，也就是某些类别只有一个例子：比如班主任，一个班只需要一个班主任。</p>
<p>或者我们只是要提供一个通用的方法库这种情况下，可以使用这种编程模式。</p>
<p>这就是一种编程方法，我们把东西都放到类中。然后使用类变量来调用global set of function 或者data.我们不需要进行实例化或者其他的操作、</p>
<p>换句话说，我们就是把class 像namespace这样来用。</p>
<p>Singleton 就是组织大量全局变量和static function的方法，将这些组合成一个blob。</p>
<p><strong>阻止实例化</strong></p>
<ol>
<li>可以通过把构造函数设置为私有来阻止实例化操作，但是还是会存在缺陷，还是可以通过下面的操作来类似的实例化；</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">Singleton</span> <span class="n">instance</span> <span class="o">=</span> <span class="n">Singleton</span><span class="o">::</span><span class="n">Get</span><span class="p">();</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="2">
<li>但是这样的话会把我们singleton的数据都复制一次（每执行一次复制一次），所以我们需要去除复制构造函数来防止这种操作的实现。这样的话，我们最多就是使用&amp;来使用一个别名进行这个singleton的调用（在上面那个定义加入<code>&amp;</code> -&gt;<code>Singleton&amp;</code>）</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">	<span class="n">Singleton</span><span class="p">(</span><span class="k">const</span> <span class="n">Singleton</span><span class="o">&amp;</span><span class="p">)</span> <span class="o">=</span> <span class="k">delete</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="3">
<li>标准的单例调用模式存在一定的麻烦（代码块1），如果我们希望去掉Get来优化调用的过程：可以在定义的时候修改成（代码块2）</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">Random</span><span class="o">::</span><span class="n">Get</span><span class="p">().</span><span class="n">Float</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 先获得单例，然后调用函数
</span></span></span><span class="line"><span class="cl"><span class="c1">// 或者使用下面的方式
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">auto</span><span class="o">&amp;</span> <span class="n">random</span> <span class="o">=</span> <span class="n">Random</span><span class="o">::</span><span class="n">Get</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="kt">float</span> <span class="n">number</span> <span class="o">=</span> <span class="n">random</span><span class="p">.</span><span class="n">Float</span><span class="p">();</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">static</span> <span class="kt">float</span> <span class="n">Float</span><span class="p">()</span> <span class="p">{</span><span class="k">return</span> <span class="nf">Get</span><span class="p">().</span><span class="n">IFloat</span><span class="p">();}</span>
</span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">	<span class="kt">float</span> <span class="n">IFloat</span><span class="p">()</span> <span class="p">{</span><span class="k">return</span> <span class="n">m_RandomGenerator</span><span class="p">;}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>单例通常使用::在外面定义</strong>，就像下面大图的nullptr</p>
<p>但是如果我们不希望这样（不希望自己在外面进行一个初始化）我们可以写成（写在get里，那么初次调用的时候会生成类static的singleton）（这也是结合了后面修正的<strong>最终版</strong>）（分析一下这些static）第一次生成，后面全是singleton引用。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Singleton_origin</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">	<span class="c1">// 构建一个通用的单例指针
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="k">static</span> <span class="n">Singleton_origin</span><span class="o">*</span> <span class="n">s_Instance</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">	<span class="c1">// 通过Get返回指针所指向的singleton对象
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="k">static</span> <span class="n">Singleton_origin</span><span class="o">&amp;</span> <span class="n">Get</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">	<span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="o">*</span><span class="n">s_Instance</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="c1">// 每个Singleton_origin class 的实例中的通用Function
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="kt">void</span> <span class="nf">hello</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">	<span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="n">Singleton_origin</span><span class="o">*</span> <span class="n">Singleton_origin</span><span class="o">::</span><span class="n">s_Instance</span> <span class="o">=</span> <span class="k">nullptr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// TYPE2: 实际构建一个singleton怎么去做
</span></span></span><span class="line"><span class="cl"><span class="c1">// 这一步还没有对复制的情况以及调用的麻烦的情况进行优化，结合下面的最终版。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">class</span> <span class="nc">Singleton</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">	<span class="k">static</span> <span class="n">Singleton</span><span class="o">&amp;</span> <span class="n">Get</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">	<span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="c1">// 这个静态的instance只会在初次调用这个GET的时候生成，后续的话就是直接return他了。所以这样写就行
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="c1">// 需要注意的是，由于我们返回的类型设定为reference（&amp;），所以如果我们去掉的了↓的static关键词，就会出错
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="c1">// 因为reference返回的是别名，也就是需要这个值一直存在，不然在后续的使用中会出现问题，而不是返回一个copy，当然也可以去掉函数中的&amp;。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="c1">// 所以我们需要借助static 关键词，来延长这个instance的声明周期，才会被正确的使用。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="c1">// 这种只有第一次起到作用的方法，就适用于很多需要初始化的场景。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="k">static</span> <span class="n">Singleton</span> <span class="n">instance</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="n">instance</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="kt">void</span> <span class="nf">hello</span><span class="p">()</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="c1">//Singleton_origin::Get().hello();
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="n">Singleton</span><span class="o">::</span><span class="n">Get</span><span class="p">().</span><span class="n">hello</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="n">std</span><span class="o">::</span><span class="n">cin</span><span class="p">.</span><span class="n">get</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>最终版</strong> 集成了上面的全部优点，简化了调用，不会进行复制，不需要在类外进行单例的初始化。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">	<span class="n">Random</span><span class="p">(</span><span class="k">const</span> <span class="n">Random</span><span class="o">&amp;</span><span class="p">)</span> <span class="o">=</span><span class="k">delete</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	
</span></span><span class="line"><span class="cl">	<span class="k">static</span> <span class="n">Random</span><span class="o">&amp;</span> <span class="n">Get</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">	<span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="k">static</span> <span class="n">Random</span> <span class="n">instance</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="n">instance</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	
</span></span><span class="line"><span class="cl">	<span class="k">static</span> <span class="kt">float</span> <span class="nf">Float</span><span class="p">()</span> <span class="p">{</span><span class="k">return</span> <span class="n">Get</span><span class="p">().</span><span class="n">IFloat</span><span class="p">();}</span>
</span></span><span class="line"><span class="cl"><span class="k">private</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">	<span class="kt">float</span> <span class="n">IFloat</span><span class="p">()</span> <span class="p">{</span><span class="k">return</span> <span class="n">m_RandomGenerator</span><span class="p">;}</span>
</span></span><span class="line"><span class="cl">	<span class="n">Random</span><span class="p">(){}</span>
</span></span><span class="line"><span class="cl">	<span class="kt">float</span> <span class="n">m_RandomGenerator</span> <span class="o">=</span> <span class="n">o</span><span class="mf">.5f</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="结构体structure">结构体（Structure）</h3>
<p>实际上就是一个默认是Public的Class，Class是反过来的。</p>
<ol>
<li>
<p>什么时候该用结构体什么时候该用类？</p>
<p><strong>默认情况</strong>下：class是私有的，类或属性（需要共有的时候要public）；而Struct是默认公有的（需要私有的时候要用private）；</p>
</li>
<li>
<p>这是唯一的区别，但是在代码实际使用的时候还是有所不同的：<strong>存在的原因</strong></p>
<ol>
<li>保持和c之间的兼容性</li>
<li>或者我们想要全都用public的时候。</li>
</ol>
</li>
<li>
<p>自定义使用场景（规定编程风格）</p>
</li>
<li>
<ol>
<li>Plain old data（pod）的时候喜欢更多的用struct，就是仅仅只代表一堆变量的时候。比如说<strong>定义向量</strong>，这中类似的数据体的时候</li>
<li>“我将永远不会对struct使用继承”</li>
</ol>
</li>
</ol>
<h3 id="公用体unions">公用体（Unions）</h3>
<p>是一种类似Struct的结构，但是同时只能存在一个member（变量），无论你声明了多少个，实际上都是共享内存空间（地址）的，所以如果我们declaration的Type不同，就可能会出现Type Punning的现象，实际上也可以理解为一个变量的多个别名？</p>
<p><a href="https://www.runoob.com/cprogramming/c-unions.html" target="_blank" rel="noopener">菜鸟教程</a>
，<a href="https://zh.cppreference.com/w/cpp/language/union" target="_blank" rel="noopener">CPP reference</a>
</p>
<ul>
<li>但是通常<strong>匿名使用</strong>，也就是只使用其<strong>只能有一个member的特性</strong>，很多时候会放置再Struct 之类的里面。和Struct一起匿名使用是不影响我们的调用层级结构的</li>
<li>存储空间的大小以最大的成员作为标准好像</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">Vet2</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">float</span> <span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">Vet4</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">union</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">struct</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="kt">float</span> <span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">,</span><span class="n">z</span><span class="p">,</span><span class="n">w</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">};</span>
</span></span><span class="line"><span class="cl">        <span class="k">struct</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">Vet2</span> <span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 这样的话
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">Vet4</span> <span class="n">v</span> <span class="o">=</span> <span class="p">{</span><span class="mf">1.0f</span><span class="p">,</span><span class="mf">2.0f</span><span class="p">,</span><span class="mf">3.0f</span><span class="p">,</span><span class="mf">4.0f</span><span class="p">};</span> 
</span></span><span class="line"><span class="cl"><span class="c1">//v.x 实际上和 v.a.x 是一样的,他们共享了一样的内存地址，这个和type punning有点像。
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="结构体绑定structured-binding">结构体绑定（Structured binding）</h3>
<p>这一部分实际上解决的是，我们使用struct的方式来实现多类回归的情况：[linkto](#Func: 多值输出 (Multiple Return)),所以参考那一部分就好了</p>
<h2 id="part-5-workflow逻辑控制">Part 5 WorkFlow&amp;逻辑控制</h2>
<p>This Part 介绍一些算法的逻辑控制以及workflow控制，包括循环，条件，<strong>函数</strong>，线程之类的，控制工作流的内容。</p>
<h3 id="func-基本的函数定义functions">Func： 基本的函数定义（Functions）</h3>
<p>其实没啥特别好说的就是：</p>
<ul>
<li><strong>一般在header 中写入declaration，然后把definition写在Cpp files里面。</strong></li>
<li>其实定义的<strong>全局变量</strong>在function中也是可以<strong>直接调用</strong>的，不需要重新导入之类的。这个应该都是懂的吧</li>
<li>:star: Always pass you object by const reference!总是使用const和reference传入我们的参数。</li>
<li>需要副本就复制.</li>
</ul>
<h3 id="func-匿名函数lambdas">Func： 匿名函数（Lambdas）</h3>
<p>参考资料：<a href="https://zhuanlan.zhihu.com/p/143884880" target="_blank" rel="noopener">lambda详细教程</a>
，<a href="https://blog.csdn.net/guotianqing/article/details/103460612" target="_blank" rel="noopener">捕获值理解</a>
</p>
<p>匿名函数实际上是用于基本上一次性的函数：我们不需要真正的（实际的）对函数进行定义。</p>
<p>基本定义方式：<code>[capture](传入参数){实现内容}</code></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">auto</span> <span class="n">lambda</span> <span class="o">=</span> <span class="p">[](</span><span class="kt">int</span> <span class="n">value</span><span class="p">){</span><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="o">&lt;&lt;</span><span class="s">&#34;Value:&#34;</span><span class="o">&lt;&lt;</span><span class="n">value</span><span class="o">&lt;&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;};</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 调用的时候
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">lambda</span><span class="p">(</span><span class="mi">5</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>
<p>需要传入外部数据的时候就需要使用Capture，比如main中的值，用&amp;or =；如果我们要使用Capture的时候，我们可能要<code>#include&lt;functional&gt;</code></p>
</li>
<li>
<p><strong>Question:</strong> lambda的传入的参数默认是不能修改的，要修改的话我们需要加入mutable关键词（在传入参数和实现内容之间）</p>
</li>
</ul>
<p>其他的lambda实例：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="n">values</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">find_if</span><span class="p">(</span><span class="n">values</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">values</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="p">[](</span><span class="kt">int</span> <span class="n">value</span><span class="p">){</span><span class="k">return</span> <span class="n">value</span><span class="o">&gt;</span><span class="mi">3</span><span class="p">;});</span>
</span></span><span class="line"><span class="cl"><span class="c1">// it actually is👇 返回第一个&gt;3的值
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">find_if</span><span class="p">(</span><span class="n">values</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">values</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="p">[](</span><span class="kt">int</span> <span class="n">value</span><span class="p">){</span><span class="k">return</span> <span class="n">value</span><span class="o">&gt;</span><span class="mi">3</span><span class="p">;});</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="o">&lt;&lt;</span> <span class="o">*</span><span class="n">it</span> <span class="o">&lt;&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="func三元运算符ternary-operator">Func：三元运算符（Ternary Operator）</h3>
<p><strong>条件表达式？表达式1：表达式2</strong></p>
<p>这种形式实际上和python中的如下的表达式一致</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">Flag</span> <span class="o">=</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl"><span class="n">a</span> <span class="o">=</span> <span class="mi">5</span> <span class="k">if</span> <span class="n">Flag</span> <span class="k">else</span> <span class="mi">10</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>c++中表示为如下</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">s_Speed</span> <span class="o">=</span> <span class="n">s_Level</span> <span class="o">&gt;</span> <span class="mi">5</span><span class="o">?</span> <span class="mi">10</span><span class="o">:</span> <span class="mi">5</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">s_Speed</span> <span class="o">=</span> <span class="n">s_Level</span> <span class="o">&gt;</span> <span class="mi">5</span><span class="o">?</span> <span class="n">s_Level</span> <span class="o">&gt;</span><span class="mi">10</span><span class="o">?</span> <span class="mi">15</span><span class="o">:</span> <span class="mi">10</span><span class="o">:</span> <span class="mi">5</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="func-多值输出-multiple-return">Func: 多值输出 (Multiple Return)</h3>
<p>include新报本的结构体绑定方式。</p>
<p>由于C++本身的Type机制，我们没办法在func中同时<strong>直接</strong>return不同类型。</p>
<ul>
<li>
<p>而如果我们试图return同一type的多个value的话，我们实际上可以用return<strong>vector或者array</strong>的方式实现，当然这就是一种比较蠢的操作了。</p>
<blockquote>
<p>stdarray或者传统的array</p>
<p>好像也可以使用tuple的方式{v1,v2}同个类型的多个值</p>
</blockquote>
</li>
<li>
<p><strong>推荐：<strong>当然聪明一点的方法就是，我们定义一个struct，包含我们需要的这些所有type，然后</strong>return这个struct</strong>就好了</p>
</li>
<li>
<p>还有一种方法就是使用**&amp;来传递参数**，就不需要return了，设置为void就可以了</p>
<blockquote>
<p>也可以用指针的方式，指针方式的好处就是可以是空值</p>
</blockquote>
</li>
</ul>
<p><strong>C++的默认指定方式：tuple和pair</strong></p>
<p>用tuple类型的方式操作起来有点麻烦啊如下，但是也可以混杂多种类型输出。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="cp">#import &lt;tuple&gt;
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="k">static</span> <span class="n">std</span><span class="o">::</span><span class="n">tuple</span><span class="o">&lt;</span><span class="n">type1</span><span class="p">,</span><span class="n">typw2</span><span class="o">&gt;</span> <span class="n">func</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">//return std::make_pair&lt;type1,type2&gt;(var1,var2);
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">//上面的type指定有时候也能省略
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">//或者使用下面这种方式,上面那种实际上是pair类型的返回把
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">return</span> <span class="p">{</span><span class="n">var1</span><span class="p">,</span><span class="n">var2</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">auto</span> <span class="p">[</span><span class="n">name</span><span class="p">,</span> <span class="n">age</span><span class="p">]</span> <span class="o">=</span> <span class="n">func</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="c1">// c++ 标准更新以后tuple的使用方法变得更加的好用了。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    
</span></span><span class="line"><span class="cl"><span class="o">------------------</span><span class="err">👆</span><span class="n">NEW</span> <span class="n">Version</span> <span class="o">&amp;</span> <span class="n">Called</span> <span class="n">Structure</span> <span class="n">Binding</span><span class="o">----------------</span>
</span></span><span class="line"><span class="cl"><span class="o">--------------------------------</span><span class="err">👇</span><span class="n">OLD</span> <span class="n">VERSION</span> <span class="o">&lt;</span><span class="n">c</span><span class="o">++</span><span class="mi">17</span><span class="o">----------------------</span>
</span></span><span class="line"><span class="cl"><span class="c1">//std::tuple&lt;type1,type2&gt; a = func();
</span></span></span><span class="line"><span class="cl"><span class="c1">////或者
</span></span></span><span class="line"><span class="cl"><span class="c1">//auto a = func();
</span></span></span><span class="line"><span class="cl"><span class="c1">////oldversion要取出元素的时候我们还需要
</span></span></span><span class="line"><span class="cl"><span class="c1">//std::string&amp; name=std::get&lt;0&gt;(a); //这里可以用&amp;防止动态的内存copy的情况
</span></span></span><span class="line"><span class="cl"><span class="c1">//std::get&lt;1&gt;(a);
</span></span></span><span class="line"><span class="cl"><span class="c1">////所以这边建议使用struct
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">//// 取出元素的第二种方法.
</span></span></span><span class="line"><span class="cl"><span class="c1">//std::string name;
</span></span></span><span class="line"><span class="cl"><span class="c1">//int age;
</span></span></span><span class="line"><span class="cl"><span class="c1">//std::tie(name,age) = func();
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="threads线程操作">Threads：线程操作</h3>
<p>函数编写过程中的多线程操作和线程管理，下面是一个典型的例子，我们<strong>好像</strong>也可以使用进程去建立一个线程对象。</p>
<p>使用线程主要的目的是为了1. 完成单线程没法完成的事情以及2. 优化一些算法的运行速度。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;thread&gt;</span><span class="cp"> </span><span class="c1">//支撑线程的基准库
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">bool</span> <span class="n">Flag</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 编写一个函数用于子进程的执行，通常使用函数指针的方式调用
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kt">void</span> <span class="nf">DoWork</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="nb">true</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="o">&lt;&lt;</span><span class="s">&#34;Working... </span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">std</span><span class="o">::</span><span class="n">this_thread</span><span class="o">::</span><span class="n">sleep_for</span><span class="p">(</span><span class="mi">1</span><span class="n">s</span><span class="p">);</span> <span class="c1">//休眠这个进程1s，防止疯狂打印
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="kr">thread</span> <span class="n">worker</span><span class="p">(</span><span class="n">DoWork</span><span class="p">);</span> <span class="c1">//使用一个进程去执行Dowork
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">cin</span><span class="p">.</span><span class="n">get</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="n">Flag</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span> <span class="c1">//使得子进程得以结束。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    
</span></span><span class="line"><span class="cl">    <span class="n">worker</span><span class="p">.</span><span class="n">join</span><span class="p">();</span><span class="c1">//等待到子进程结束，再继续主进程
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">std</span><span class="o">::</span><span class="n">cin</span><span class="p">.</span><span class="n">get</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>如果我们再调用某个进程的时候想看当前的ID，也可以再运行的函数中加入<code>STD::this_thread::get_id()</code>得到当前进程的ID。当然我们每次运行可能都是不一样的。</p>
<h3 id="threads多线程管理">Threads：多线程管理</h3>
<p><strong>这一部分没有英文字幕，缺失了很多信息，后续使用到的时候进行补充和修正把。</strong></p>
<p>线程并行；异步；等等的多线程管理。<code>std::async</code></p>
<p>对于<strong>independent</strong>的Application和Function Part，实际上很多操作我们可以在cpu和memory上并行进行，对不相关的任务进行分布（异步），对相关的任务有所约束（同步），合理的对进程进行调度，能够使得我们对资源有更充分的利用，同时也能提升程序的运行速度。</p>
<p>对于不依赖于运行次序的一些操作：比如载入很多模型或者数据（num_worker）</p>
<p><a href="https://zh.cppreference.com/w/cpp/thread/async" target="_blank" rel="noopener">cppref参考页面</a>
；<a href="https://www.cnblogs.com/IT-CPC/p/10898871.html" target="_blank" rel="noopener">异步合同的概念</a>
；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="cp">#include&lt;future&gt;
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="k">static</span> <span class="n">std</span><span class="o">::</span><span class="n">mutex</span> <span class="n">s_meshesMutex</span><span class="p">;</span> <span class="c1">//解决1. 针对变量定义一个互斥锁
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">static</span> <span class="kt">void</span> <span class="nf">LoadMesh</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">Ref</span><span class="o">&lt;</span><span class="n">Mesh</span><span class="o">&gt;&gt;&amp;</span> <span class="n">meshes</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">filepath</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">auto</span> <span class="n">mesh</span> <span class="o">=</span> <span class="n">Mesh</span><span class="o">::</span><span class="n">Load</span><span class="p">(</span><span class="n">filepath</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="c1">//解决1. 使用lock，锁住我们可能需要修改的这个变量，使得一个thread在进行修改的时候，🔒（其余不能对该变量进行操作），修改完成解锁🔑；
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">std</span><span class="o">::</span><span class="n">Lock_guard</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">mutex</span><span class="p">)</span> <span class="n">lock</span><span class="p">(</span><span class="n">s_meshexMutex</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">meshes</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">mesh</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">file</span> <span class="p">:</span> <span class="n">filelist</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">//1. 异步使用文件载入，但是这样会出现问题，就是当我们两个进程同时进行修改操作的时候怎么办？
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="n">m_Futures</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">async</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">lauch</span><span class="o">::</span><span class="n">async</span><span class="p">,</span><span class="n">LoadMesh</span><span class="p">,</span><span class="n">m_Meshes</span><span class="p">,</span><span class="n">filelist</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>为了防止同时的写入操作，我们还需要Lock操作去锁住可能会修改的变量。同时好像异步程序的返回值比较特殊，所以我们需要在头文件中进行如下定义：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">future</span><span class="o">&lt;</span><span class="kt">void</span><span class="o">&gt;&gt;</span> <span class="n">m_Future</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>此外我们可以控制是否执行异步程序（老办法了）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="cp">#define ASYNC 1
</span></span></span><span class="line"><span class="cl"><span class="cp">#if ASYNC
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>	<span class="n">ASYNCfunc</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="cp">#else
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>	<span class="n">func</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="cp">#endif</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>最后我们可以在debug的时候 windows ，parallel stacks找到进程表（很吊）。好像也可以在执行代码的地方跳到正在执行的某个进程</p>
<h3 id="benchmark基准测试">Benchmark：基准测试</h3>
<p>在运行程序的时候如何监控我们该<strong>代码的性能</strong>（<strong>运行时间</strong>等等），或者测试新方法的方式。这里给出了他的方式。实际上有很多不同的方式。</p>
<p><code>_debugbreak()</code>: 类似python中的raise exception</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="c1">// 简单的范例，
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">Timer</span> <span class="n">timer1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">func</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">...;</span>
</span></span><span class="line"><span class="cl">    <span class="n">_debugbreak</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>我们要确信的一点是，计时器是否真正的测量了运行的时间，因为有时候编译器会直接进行中间态计算，所以实际运行的时候，就会没有计算到开销。</p>
<p><strong>测量share pointer和unique pointer</strong></p>
<p>unique&gt;make share &gt;new share</p>
<h4 id="visual-benchmarking-可视化">Visual Benchmarking （可视化）</h4>
<p>使用<code>chrome:://tracing</code> 在浏览器中进行可视化,这一课作为补充资料把。暂时不需要用这种方式</p>
<h3 id="switchcase-分支">Switch：case 分支</h3>
<p>一个 <strong>switch</strong> 语句允许测试一个变量等于多个值时的情况。每个值称为一个 case，且被测试的变量会对每个 <strong>switch case</strong> 进行检查。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">switch</span><span class="p">(</span><span class="n">expression</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="n">constant</span><span class="o">-</span><span class="nl">expression</span>  <span class="p">:</span>
</span></span><span class="line"><span class="cl">       <span class="n">statement</span><span class="p">(</span><span class="n">s</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">       <span class="k">break</span><span class="p">;</span> <span class="c1">// 可选的
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">case</span> <span class="n">constant</span><span class="o">-</span><span class="nl">expression</span>  <span class="p">:</span>
</span></span><span class="line"><span class="cl">       <span class="n">statement</span><span class="p">(</span><span class="n">s</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">       <span class="k">break</span><span class="p">;</span> <span class="c1">// 可选的
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  
</span></span><span class="line"><span class="cl">    <span class="c1">// 您可以有任意数量的 case 语句
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">default</span> <span class="o">:</span> <span class="c1">// 可选的
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>       <span class="n">statement</span><span class="p">(</span><span class="n">s</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="workflowconditions-and-branches-条件和分支">Workflow：Conditions and Branches 条件和分支</h3>
<p>if 指令实际上是检查<strong>值是否为0</strong>，0 == False， !0 ==True;</p>
<p>Keyword：<code>if</code>; <code>else if</code>; <code>else</code>;</p>
<h3 id="loops-for-and-while-循环定义">Loops: For and While 循环定义</h3>
<ol>
<li>
<p><strong>For 循环其实就是 （声明变量；condition；迭代规则）</strong></p>
<p>我们可以直接在括号里写，也可以全部写在外面</p>
<p>condition要声明，但是可以在外面定义</p>
</li>
<li>
<p><strong>While （condition）</strong></p>
</li>
<li>
<p><strong>Do {</strong></p>
<p><strong>}While（condition）</strong></p>
<p>即使条件为false也至少能执行一次</p>
</li>
</ol>
<h3 id="workflow-control-flow-contiune-break--return-循环控制">Workflow: Control Flow (contiune, break , return) 循环控制</h3>
<p>这几个关键词的使用和含义基本是和Python一致的，但是这里的Break还用于switch</p>
<h3 id="workflow-iterators迭代器">Workflow： Iterators迭代器</h3>
<p>迭代器的一些基本的参数：first（key），（当然这个是以这种形式存在的是时候才有的）second（value）；it本身是以指针形式存在的？</p>
<p>是一种对dataset中的数据进行迭代的方式，这就是一种迭代器，有点像是运算符重载，通常用于对数据结构进行迭代（遍历）。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"> <span class="c1">//最常见的方式就不再说了，。vector.size()来循环就行了
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="cp">#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="c1">// type1 内置的迭代器，也是常用的使用方式。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">values</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="nl">value</span> <span class="p">:</span> <span class="n">values</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">value</span><span class="o">&lt;&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// type2 使用内置的iterator，还有反向的iterator，但是正常人谁用这个啊
</span></span></span><span class="line"><span class="cl"><span class="c1">// 这里注意到it是一堆指针，我们如果要取值的话需要解除指针。*
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">for</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;::</span><span class="n">iterator</span> <span class="n">it</span> <span class="o">=</span> <span class="n">values</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span> <span class="n">it</span> <span class="o">!=</span> <span class="n">values</span><span class="p">.</span><span class="n">end</span><span class="p">();</span> <span class="n">it</span><span class="o">++</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="o">&lt;&lt;*</span><span class="n">it</span><span class="o">&lt;&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>那么我们如何对于<strong>无序的数集</strong>(实际上unorder_map是Hash的C++实现)来进行迭代或者遍历呢？，看下面这个例子：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;unordered_map&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="k">using</span> <span class="n">ScoreMap</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">unordered_map</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">//std::unordered_map&lt;std::string, int&gt; map;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">ScoreMap</span> <span class="n">map</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">map</span><span class="p">[</span><span class="s">&#34;aiken&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">map</span><span class="p">[</span><span class="s">&#34;c++&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 由于无序图没有index，经典的就是使用这样的方式
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">for</span> <span class="p">(</span><span class="n">ScoreMap</span><span class="o">::</span><span class="n">const_iterator</span> <span class="n">it</span> <span class="o">=</span> <span class="n">map</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span> <span class="n">it</span> <span class="o">!=</span> <span class="n">map</span><span class="p">.</span><span class="n">end</span><span class="p">();</span> <span class="n">it</span><span class="o">++</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">auto</span><span class="o">&amp;</span> <span class="n">key</span> <span class="o">=</span> <span class="n">it</span><span class="o">-&gt;</span><span class="n">first</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">auto</span><span class="o">&amp;</span> <span class="n">value</span> <span class="o">=</span> <span class="n">it</span><span class="o">-&gt;</span><span class="n">second</span><span class="p">;</span> <span class="c1">//second 应该指的是value把，但是对于多元素的hash怎么处理？
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">PRINT_FUC</span> <span class="n">HERE</span><span class="p">.</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 仿照上面那种更方便的方式来编写迭代的话(这里的auto 实际上是pair的形式)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">kv</span> <span class="p">:</span> <span class="n">map</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">auto</span><span class="o">&amp;</span> <span class="n">key</span> <span class="o">=</span> <span class="n">kv</span><span class="o">-&gt;</span><span class="n">first</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">auto</span><span class="o">&amp;</span> <span class="n">value</span> <span class="o">=</span> <span class="n">kv</span><span class="o">-&gt;</span><span class="n">second</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">PRINT_FUC</span> <span class="n">HERE</span><span class="p">.</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 当然还有一种梦寐以求的方式，后续可能我们会最常用的方式
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="p">[</span><span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">]</span> <span class="o">:</span> <span class="n">map</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">key</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;=&#34;</span> <span class="o">&lt;&lt;</span> <span class="n">value</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>编写我们自己Structure中的Iterator</strong>：</p>
<p>假设：这是不是应该使用类似linklist之类的方式，将数据通过类似指针的方式迭代的串起来？</p>
<p>这一部分太长了，还是参考<a href="https://www.youtube.com/watch?v=F9eDv-YIOQ0&amp;list=PLlrATfBNZ98dudnM48yfGUldqGD0S4FFb&amp;index=94&amp;ab_channel=TheCherno" target="_blank" rel="noopener">视频94</a>
把，我就直接重载[]和size通过for去做迭代器了，建议加入相关的.cpp，不要集成在文档中。</p>
<p>这一部分其实可以帮助对一些重载，还有一些vector机制有一个更好的理解，以及一些动态的内存管理，可以自己在后续编写一下试试。</p>
<h3 id="workflow-continuous-integration-ci-持续集成">Workflow: Continuous Integration CI （持续集成）</h3>
<p>每次commit后都build 以及run &amp;test就是CI吗？</p>
<p>“持续集成是一种软件开发实践，即团队开发成员经常集成他们的工作，通常每个成员每天至少集成一次，也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建（包括<a href="https://baike.baidu.com/item/%e7%bc%96%e8%af%91/1258343" target="_blank" rel="noopener">编译</a>
，发布，自动化测试）来验证，从而尽早地发现集成错误。”</p>
<p>使用：jenkins（第86课）</p>
<h3 id="workflow-static-analysis静态代码分析">Workflow: Static Analysis(静态代码分析)</h3>
<p>也就是一些分析工具，比如pylint之类的东西；</p>
<p>Cherno推荐：PVS-Studio</p>
<h2 id="part-6--memory-资源管理">Part 6  Memory 资源管理</h2>
<p>This Section 我们从memory出发来谈及关于Stack，Heap之类的内存管理和优化方法,以及编写的safe。</p>
<p><a href="https://www.cnblogs.com/2sheep2simple/p/10680347.html" target="_blank" rel="noopener">粗略：Heap和Stack的区别</a>
；<a href="https://www.cnblogs.com/iostream7/archive/2010/12/08/1900279.html" target="_blank" rel="noopener">进阶1：C++中内存分配，堆（Heap）与栈（Stack）区别</a>
</p>
<p><a href="https://www.zhihu.com/question/281940376" target="_blank" rel="noopener">为什么c++中要分为heap（堆）和stack（栈）</a>
</p>
<h3 id="stack-vs-heap-c中的内存栈与堆">Stack vs Heap: C++中的内存栈与堆</h3>
<p><code>char* buffer = new char[8]</code> 定义一个8个字节的内存空间，并返回指向内存开始的地址的指针</p>
<p><strong>基本概念</strong>：stack和heap都是内存（RAM）中实际存在的单元</p>
<ul>
<li>stack存在预定义的长度: 2M左右。</li>
<li>heap虽然已有预设的默认值，但会随着我们的Application去更改大小</li>
<li>目的都是为我们的程序和全局或者局部变量提供存储空间。</li>
<li>不同的内存分配方式。</li>
<li>memset可以用来填充内存块</li>
<li>memcpy 内存拷贝，拷贝内存块</li>
</ul>
<p>**基本定义方式：**前面一般是定义在stack上的，后半部分是定义在heap上的</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">value</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">array</span><span class="p">[</span><span class="mi">5</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="n">ClassA</span> <span class="n">vector</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="kt">int</span><span class="o">*</span> <span class="n">hvalue</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="o">*</span><span class="n">havalue</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span><span class="o">*</span> <span class="n">harray</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="p">[</span><span class="mi">5</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="n">ClassA</span><span class="o">*</span> <span class="n">hvector</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ClassA</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>分配方式上的区别</strong>（主要是<strong>new</strong>）</p>
<ol>
<li><strong>stack</strong>上分配的内存空间是<strong>连续的</strong>，实际上就是栈顶的指针移动需要的距离，然后重新赋予数值。每一个在另一个上面。
<ol>
<li>所以这样分配会比较快，我们只需要在寄存器上移动指针的地址就可以了</li>
<li>{}实际上就是一个stack，超出这个作用域后，栈内的数据会自动销毁，也就是实际上就是将指针还原到了作用域开始的地方。Free操作实际上只是指针的移动。</li>
</ol>
</li>
<li>heap上分配的内存空间是随机的。
<ol>
<li>实际上会call <code>malloc</code>，给你一个指定大小的内存块，同时也会管理一个<strong>需要</strong>free-list的内存列表（也就是已经申请了的列表），</li>
<li>所以在heap上<strong>分配</strong>空间实际上是一整套任务，而在stack上实际上就是指针移动，他们两个的效率是完全不一样的。但是有各自面对的状况吧。</li>
<li>需要大量数据，或者说是，需要延长生存周期的话都需要用heap。</li>
</ol>
</li>
<li>在debug model中的汇编之类的机器代码是没有经过精简的，但是release后vs会自己优化。</li>
</ol>
<h3 id="newkeyword-for-mem内存关键词">New：Keyword For Mem内存关键词</h3>
<p>使用new实际上是一系列命令（运算符重载），包括在空闲的内存块中占用一块指定大小的内存，所以会<strong>需要时间</strong>；</p>
<p>基本准则：<strong>有new有Delete；无new 无delete</strong></p>
<ul>
<li>new经常和数组一起使用来获得指定大小的heap空间</li>
<li>new在使用的时候也会调用constructor（构造函数），相应的delete；</li>
<li>new -&gt;delete; new [] -&gt; delete [];</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">int</span><span class="o">*</span> <span class="n">b</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span> <span class="p">[</span><span class="mi">50</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="n">Entity</span><span class="o">*</span> <span class="n">e</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Entity</span><span class="p">[</span><span class="mi">50</span><span class="p">];</span> <span class="c1">//这种情况下同时会调用构造函数
</span></span></span><span class="line"><span class="cl"><span class="c1">//虽然我们可以用malloc指令定义，但是这种方式不会调用析构函数，所以千万不要用这种方法。
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>具体的底层原因：</p>
<blockquote>
<p>new底层其实是call了malloc，malloc是memory allocation的简写，从名字也可以知道它负责分配内存，delete则调用了free()。区别是new和delete不仅管理内存，还会调用constructor和destructor，另外它们都是operator，所以你可以重载它们，做一些有趣的事情。</p>
<p>对了，new【】和delete【】其实另两个operator，它们做的事情稍微有点不一样，你调用new【】的时候，必须要指定一个size，但调用delete【】的时候，并没有指定size，它怎么知道delete多少呢？这是因为new【】不仅分配了所需要的内存，还会多分配一个额外的空间，来存储这个size，所以以视频中的举例，它所做的是分配这样一块内存【8, 0, 0, 0, 0, 0, 0, 0, 0】，连续的，但是多一块在最前面，但是return给你的是跳过那块内存的地址，比如malloc返回的是0x1，但new【】给你返回的是0x1+2（我记得它分配的是一个word（一般是short）的大小，具体大小需要看系统），然后在delete【】的时候，它会往前推一个word，因为它知道前面一个word肯定是size，从而拿到size，进而delete所有）</p>
</blockquote>
<p><strong>什么时候通过New来定义实体（instance）</strong></p>
<ul>
<li>
<p>就是如果我们希望在一个Function中定义类的实体的时候，为了延长生命周期，我们需要将实体定义在heap上</p>
</li>
<li>
<p>或者是class 规模太大，但是stack太小了，所以我们要借助heap的存储空间</p>
</li>
<li>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">Entity</span><span class="o">*</span> <span class="n">entity</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Entity</span><span class="p">(</span><span class="s">&#34;Cherno&#34;</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
</ul>
<h3 id="safety使用智能指针的情景">Safety：使用智能指针的情景</h3>
<p>什么样的程序是safe的？减少崩溃和内存泄漏的情况，也就是让Code尽量不要越过需要的边界。This Part is about Smart Pointer。</p>
<p>实际上安全性和内存分配是分不开的。</p>
<ul>
<li>对自己所有allocated的memory负责，所以智能指针特别屌，应该**100%使用智能指针，不要仅仅使用原生指针（Raw Poniter），能不用就尽量不用。**智能指针我们就不需要担心delete或者内存泄漏等等的问题了。</li>
<li>Raw Poniter在我们使用的小规模程序的时候偷懒，因为只要使用※，他不安全，就只是好读和简单。</li>
<li>所以就是，使用smart pointer，当然在确保安全的情况下，我们也可以用raw pointer自由选择反正。优点和缺点就是这样了。</li>
</ul>
<h3 id="track-memory-allocation内存申请跟踪">Track Memory Allocation：内存申请跟踪</h3>
<p>优化跟踪内存管理对于计算机的性能来说相当重要，特别是我们要知道我们在哪里分配了数据。</p>
<p>虽然heap的space比较大，但是在性能至上的环境中，可能heap不会是一个最佳的选择。</p>
<p>智能指针会在heap上分配内存，（<strong>std::string都是分配在内存中的</strong>）</p>
<p><strong>Easy Way：</strong></p>
<p>这一部分能够简单的嵌入我们的任何project；(void* 存储的就是一个内存地址)</p>
<p>基本思路：重载我们的new 操作符;</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="n">import</span> <span class="o">&lt;</span><span class="n">memory</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span><span class="o">*</span> <span class="k">operator</span> <span class="k">new</span><span class="p">(</span><span class="n">size_t</span> <span class="n">size</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="o">&lt;&lt;</span><span class="s">&#34;Allocating&#34;</span><span class="o">&lt;&lt;</span><span class="n">size</span><span class="o">&lt;&lt;</span><span class="err">&#39;</span><span class="n">Bytes</span><span class="err">\</span><span class="n">n</span><span class="err">&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nf">malloc</span><span class="p">(</span><span class="n">size</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>那么当然我们也可以重载delete去检测内存的释放情况</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">void</span> <span class="k">operator</span> <span class="nf">delete</span><span class="p">(</span><span class="kt">void</span><span class="o">*</span> <span class="n">memory</span><span class="p">,</span> <span class="n">size_t</span> <span class="n">size</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="o">&lt;&lt;</span><span class="s">&#34;deleteing&#34;</span><span class="o">&lt;&lt;</span><span class="n">size</span><span class="o">&lt;&lt;</span><span class="err">&#39;</span><span class="n">Bytes</span><span class="err">\</span><span class="n">n</span><span class="err">&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">free</span><span class="p">(</span><span class="n">memory</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>那么最方便的实现方法就是我们使用一个struct来统一管理我们的内存分配情况。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">struct</span> <span class="nc">AllocationMetrics</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">uint32_t</span> <span class="n">TotalAllocated</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">uint32_t</span> <span class="n">TotalFreed</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="kt">uint32_t</span> <span class="nf">CurrentUsage</span><span class="p">(){</span><span class="k">return</span> <span class="n">TotalAllocated</span><span class="o">-</span><span class="n">TotalFreed</span><span class="p">;}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c1">//实例化全局架构
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">static</span> <span class="n">AllocationMetrics</span> <span class="n">s_AllocationMetrics</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 然后将上面的new和delete中的print改成+= 和-=
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">static</span> <span class="kt">void</span> <span class="nf">PrintUsage</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="o">&lt;&lt;</span><span class="s">&#34;usage::&#34;</span><span class="o">&lt;&lt;</span><span class="n">s_AllocationMetrics</span><span class="p">.</span><span class="n">CurrentUsage</span><span class="p">()</span><span class="o">&lt;&lt;</span><span class="s">&#34;...</span><span class="se">\n</span><span class="s">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="part-7-how-to-make-c-run-faster">Part 7 How to make C++ run Faster</h2>
<p>算法或者进程优化的部分，这一部分在做题的时候慢慢的进行填充把，在学习的时候先选择性的看看，实际上应该是Part6的延申，逃不脱资源管理的部分、</p>
<p>TODO：（已知可以但是应该暂时没用）</p>
<ul>
<li><code>std::async</code> （应该是用于进程优化） 79课</li>
<li>80 83：string优化</li>
</ul>
<h3 id="run-string-faster-优化string的运行速度">run string faster 优化string的运行速度</h3>
<p>string会在heap上allocated，所以对于性能优先的情况下不是特别推荐的,可以通过下面的方式查看heap申请。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">PrintName</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">name</span><span class="p">){}</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 想要看空间的声明，重载new就对了，看Part6
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">static</span> <span class="kt">uint32_t</span> <span class="n">s_AllocCount</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span><span class="o">*</span> <span class="k">operator</span> <span class="nf">new</span><span class="p">(</span><span class="n">size_t</span> <span class="n">size</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">s_AllocCount</span> <span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">PrintHere</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">malloc</span><span class="p">(</span><span class="n">size</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">PrintName</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">name</span><span class="p">){}</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">name</span> <span class="o">=</span> <span class="s">&#34;aiken&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">Print</span><span class="p">(</span><span class="n">name</span><span class="p">);</span> <span class="c1">//copy一次
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">name</span> <span class="o">=</span> <span class="s">&#34;aiken aiken&#34;</span><span class="p">;</span> <span class="c1">//copy
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">firstname</span> <span class="o">=</span> <span class="n">name</span><span class="p">.</span><span class="n">substr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">3</span><span class="p">);</span> <span class="c1">//copy
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">lastname</span> <span class="o">=</span> <span class="n">name</span><span class="p">.</span><span class="n">substr</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span><span class="mi">9</span><span class="p">);</span> <span class="c1">//copy 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>但是加入我们只是想要一个很简单的输出“”，不希望发生再次的construct，来增加一个string的heap空间。甚至我们使用<code>substr()</code>来输出其中的一部分，也会copy（allocation）一次原本的string。</p>
<p><strong>避免这样无意义的Copy</strong>，只是要一个指向原数据内存地址的指针，以及size把，我们可以很容易写一个这样的类，但是在C++17中官方集成了把👇</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">PrintName</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">string_view</span> <span class="n">name</span><span class="p">){}</span> <span class="c1">//这样以后print（“”）也不会分配了，原本的情况，执行print甚至都会复制一份。究极不合适
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">name</span> <span class="o">=</span> <span class="s">&#34;aiken aiken&#34;</span><span class="p">;</span> <span class="c1">//allocation only
</span></span></span><span class="line"><span class="cl"><span class="c1">//3可以修改成5 就没有allocation了,但是5的话 6，7的c_str()要去掉
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">name</span> <span class="o">=</span> <span class="s">&#34;aiken aiken&#34;</span><span class="p">;</span> <span class="c1">//not allocation 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">string_view</span> <span class="n">firstName</span><span class="p">(</span><span class="n">name</span><span class="p">.</span><span class="n">c_str</span><span class="p">(),</span><span class="mi">3</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">string_view</span> <span class="n">lastName</span><span class="p">(</span><span class="n">name</span><span class="p">.</span><span class="n">c_str</span><span class="p">()</span><span class="o">+</span><span class="mi">4</span><span class="p">,</span><span class="mi">9</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">print</span><span class="p">(</span><span class="n">firstName</span><span class="p">);</span> <span class="c1">//这种类型也不会再发生复制了
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">print</span><span class="p">(</span><span class="n">LastName</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">print</span><span class="p">(</span><span class="s">&#34;aiken aiken&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="o">----------------------------------</span><span class="err">整理如下</span><span class="o">--------------------------------------</span>
</span></span><span class="line"><span class="cl"><span class="c1">//只在定义的时候发生一次赋值。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">printname</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">string_view</span> <span class="n">name</span><span class="p">){}</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">name</span> <span class="o">=</span> <span class="s">&#34;aikenaiken&#34;</span><span class="p">;</span> <span class="c1">//allow 1(copy happen)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">std</span><span class="o">::</span><span class="n">string_view</span> <span class="n">firstName</span><span class="p">(</span><span class="n">name</span><span class="p">.</span><span class="n">c_str</span><span class="p">(),</span><span class="mi">3</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">std</span><span class="o">::</span><span class="n">string_view</span> <span class="n">lastName</span><span class="p">(</span><span class="n">name</span><span class="p">.</span><span class="n">c_str</span><span class="p">()</span><span class="o">+</span><span class="mi">4</span><span class="p">,</span><span class="mi">9</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">print</span><span class="p">(</span><span class="n">firstName</span><span class="p">);</span> <span class="c1">//这种类型也不会再发生复制了
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">print</span><span class="p">(</span><span class="n">LastName</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">print</span><span class="p">(</span><span class="s">&#34;aiken aiken&#34;</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="somthing-else-无题">Somthing Else 无题</h2>
<p>畅所欲言，或者等待归类。</p>
<ul>
<li><code>sizeof</code>通常用来获取数据的存储空间；</li>
<li><code>strlen()</code>:获取const char*的长度</li>
<li><code>alloca(size)</code>：再当前地址内存分配；所以我们可以类型转换指针（int*）</li>
<li><code>size_t</code>:可以存储各种类型大小的值,size type</li>
<li><code>constexpr</code><a href="https://www.jianshu.com/p/34a2a79ea947" target="_blank" rel="noopener">https://www.jianshu.com/p/34a2a79ea947</a>
</li>
<li><code>\</code>:编写代码的时候的换行续接符号</li>
</ul>
<p>wandbox.org ：在线编译网站</p>
<p>Visual Studio 表达式的编译顺序是从右到左运算</p>
<h3 id="argument-evaluation-order-参数输入顺序面试">Argument Evaluation Order 参数输入顺序（面试？）</h3>
<p>传入参数实际上可以是传入一个函数或者是一个表达式，我们应该规划一下这样的输入。（和++相关）</p>
<p>i ++ : 先传递在增长 ，++i：先增长在传递把</p>
<p>(<strong>undefine behavior</strong>: 意味着这种方式实际上没有被定义，也就是说是一种不可控的行为，下面是一种实例)（切换这种++的位置也是）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">Psum</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">a</span> <span class="o">&lt;&lt;</span><span class="s">&#34;+&#34;</span><span class="o">&lt;&lt;</span><span class="n">b</span> <span class="o">&lt;&lt;</span><span class="s">&#34;=&#34;</span><span class="o">&lt;&lt;</span><span class="n">a</span><span class="o">+</span><span class="n">b</span><span class="o">&lt;&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">value</span> <span class="o">=</span> <span class="mi">0</span><span class="err">；</span>
</span></span><span class="line"><span class="cl"><span class="n">Psum</span><span class="p">(</span><span class="n">value</span><span class="o">++</span><span class="p">,</span><span class="n">value</span><span class="o">++</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">//这是一种不可靠的编写方式,这个输出是不确定的，也就是一个不可靠的结果。
</span></span></span><span class="line"><span class="cl"><span class="c1">//哪个在线编译网站会告诉我们这个的编写是不确定的。有warning
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>正确答案是这种实际上是C++没有规范的，我们没法得到真实的值，但是再C++17中要求：</p>
<p>The Postfix-Expression is Sequenced before each expression in the expression-list and any default argument。</p>
<p>也就是他们需要被一个接着一个的运行。这个其实没有太听清。</p>
<p><a href="https://blog.csdn.net/samantha_wang/article/details/46942343" target="_blank" rel="noopener">https://blog.csdn.net/samantha_wang/article/details/46942343</a>
</p>
<p><a href="https://blog.51cto.com/8681495/1416759" target="_blank" rel="noopener">https://blog.51cto.com/8681495/1416759</a>
</p>
<p>也不要写像这种的</p>
<p><code>v[i] = ++i;</code></p>
]]></content:encoded>
    </item>
    <item>
      <title>FSL前期调研</title>
      <link>https://aikenh.cn/posts/fsl%E5%89%8D%E6%9C%9F%E8%B0%83%E7%A0%94/</link>
      <pubDate>Mon, 29 Nov 2021 13:12:05 +0000</pubDate>
      <guid>https://aikenh.cn/posts/fsl%E5%89%8D%E6%9C%9F%E8%B0%83%E7%A0%94/</guid>
      <description>&lt;head&gt;
    
    &lt;script src=&#34;https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/crypto-js/3.1.9-1/crypto-js.js&#34;&gt;&lt;/script&gt;
&lt;/head&gt;





&lt;div class=&#34;hugo-encryptor-container&#34;&gt;
  &lt;div class=&#34;hugo-encryptor-prompt&#34;&gt;
    
      &lt;p&gt;文章的部分内容被密码保护：&lt;/p&gt;
    
  &lt;/div&gt;
  &lt;div class=&#34;hugo-encryptor-form&#34;&gt;
    &lt;input
      class=&#34;hugo-encryptor-input&#34;
      placeholder=&#39;请输入密码&#39;
    /&gt;
    &lt;input
      class=&#34;hugo-encryptor-button&#34;
      type=&#34;button&#34;
      value=&#39;CLICK&#39;
      onclick=&#34;_click_handler(this)&#34;
    /&gt;
  &lt;/div&gt;
  &lt;div
    class=&#34;hugo-encryptor-cipher-text&#34;
    data-password=&#34;aikenhong_blog&#34;
    style=&#34;display: none;&#34;
  &gt;
    &lt;span style=&#34;display: none;&#34;&gt;--- DON&#39;T MODIFY THIS LINE ---&lt;/span&gt;
    &lt;h2 id=&#34;主要是limited-labels--few-samples--data-programing&#34;&gt;主要是limited labels &amp;amp; Few Samples &amp;amp; Data programing&lt;/h2&gt;
&lt;hr&gt;
&lt;p&gt;&lt;del&gt;Weakly supervised learning&lt;/del&gt;&lt;br&gt;
&lt;del&gt;semi-supervised in video field&lt;/del&gt;&lt;br&gt;
if we can recoding this work?&lt;br&gt;
&lt;del&gt;多指标下降（LOSS的耦合或者循环的选择）、相关的CV最新论文等等会在后续关注&lt;/del&gt;&lt;br&gt;
&lt;del&gt;元学习、浅层神经网络的概念等等&lt;/del&gt;  &lt;del&gt;semi-supervised&lt;/del&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;part1-limited-labels-base-on-lifeifeis-reference&#34;&gt;PART1 Limited Labels （base on LiFeiFei‘s reference）&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;in this part we may list the paper which is useful for my recoding.&lt;/em&gt;&lt;br&gt;
还有一些其他重要的可能在对论文进行重新精读的时候要记得注意reference：就比如说在loss变换和决策树生成那一块。&lt;br&gt;
&lt;em&gt;distant supervision(it&amp;rsquo;s kind of early) can be another baseline for our method, we need to understand how this method work for that situation&lt;/em&gt;&lt;br&gt;
distant supervisor到底是什么机制可以去CSDN什么的看一下&lt;/p&gt;</description>
      <content:encoded><![CDATA[<head>
    
    <script src="https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/crypto-js/3.1.9-1/crypto-js.js"></script>
</head>





<div class="hugo-encryptor-container">
  <div class="hugo-encryptor-prompt">
    
      <p>文章的部分内容被密码保护：</p>
    
  </div>
  <div class="hugo-encryptor-form">
    <input
      class="hugo-encryptor-input"
      placeholder='请输入密码'
    />
    <input
      class="hugo-encryptor-button"
      type="button"
      value='CLICK'
      onclick="_click_handler(this)"
    />
  </div>
  <div
    class="hugo-encryptor-cipher-text"
    data-password="aikenhong_blog"
    style="display: none;"
  >
    <span style="display: none;">--- DON'T MODIFY THIS LINE ---</span>
    <h2 id="主要是limited-labels--few-samples--data-programing">主要是limited labels &amp; Few Samples &amp; Data programing</h2>
<hr>
<p><del>Weakly supervised learning</del><br>
<del>semi-supervised in video field</del><br>
if we can recoding this work?<br>
<del>多指标下降（LOSS的耦合或者循环的选择）、相关的CV最新论文等等会在后续关注</del><br>
<del>元学习、浅层神经网络的概念等等</del>  <del>semi-supervised</del></p>
<hr>
<h3 id="part1-limited-labels-base-on-lifeifeis-reference">PART1 Limited Labels （base on LiFeiFei‘s reference）</h3>
<p><em>in this part we may list the paper which is useful for my recoding.</em><br>
还有一些其他重要的可能在对论文进行重新精读的时候要记得注意reference：就比如说在loss变换和决策树生成那一块。<br>
<em>distant supervision(it&rsquo;s kind of early) can be another baseline for our method, we need to understand how this method work for that situation</em><br>
distant supervisor到底是什么机制可以去CSDN什么的看一下</p>
<hr>
<p>Transfer Learning\label propagation算法也是这一块重要的baseline<br>
<a href="https://arxiv.org/abs/1904.11622" target="_blank" rel="noopener">Baseline</a>
：scene graph prediction with limited labels</p>
<hr>
<p><strong>reference：</strong></p>
<blockquote>
<ul>
<li><del>×<a href="https://www.semanticscholar.org/paper/Induction-of-decision-trees-Quinlan/058bb096ce1507cd65b91e341317a8ab11a675de" target="_blank" rel="noopener">Induction of decision trees</a>
</del><br>
<del>if want download, try google it</del></li>
<li><a href="https://www.semanticscholar.org/paper/01e2ed7202e357209c855927d23352b0f882c0a0" target="_blank" rel="noopener">Pattern Learning for Relation Extraction with a Hierarchical Topic Model</a>
<br>
maybe we&rsquo;ll need this paper,when we try to recoding.<br>
nope.当我们写论文需要理论基础的时候可能需要，</li>
<li>√<a href="https://www.semanticscholar.org/paper/37acbbbcfe9d8eb89e5b01da28dac6d44c3903ee" target="_blank" rel="noopener">Data Programming: Creating Large Training Sets, Quickly</a>
<br>
it&rsquo;s important to see if this article have same idea with me?</li>
</ul>
</blockquote>
<p>it&rsquo;s kind of learning paradigm,<br>
是一种构建数据集中，标注数据的范式，通过这样的method可以对多种labeling function进行整合，同时减少标注的误差和overlap情况的解决。后续我们实现方法的时候可以参考一下这个的数学理论，帮助在实际中进行应用。<br>
（本文中对这里的noise-aware的损失函数进行了应用，使其适应概率标签从而抑制噪声。）<br>
<strong>严重怀疑这是snorkel算法中的引文，直接引用过来</strong></p>
<blockquote>
<ul>
<li>×<a href="https://www.semanticscholar.org/paper/d48edf9e81653f4c3da716b037b0b50d54c5b034" target="_blank" rel="noopener">Knowledge-Based Weak Supervision for Information Extraction of Overlapping Relations</a>
<br>
figure out how can knowledge-based benefit weakly supervised learning ?<br>
nope. NIP method. 运用语言结构，类似于发的东西，来对文本进行补全。如果我们需要了解基础知识怎么使用，可以尝试参考。</li>
</ul>
</blockquote>
<blockquote>
<ul>
<li>※<a href="https://arxiv.org/pdf/1804.09170.pdf" target="_blank" rel="noopener">Realistic Evaluation of DeepSemi-Supervised Learning Algorithms</a>
NIPS 2018<br>
深度半监督学习的现实性评估：公布了统一的重新实现和评估的平台（方式？），（针对于算法在生产现实之中的适用性发布的一个标准。）<br>
based on analysis of image algorithm：半监督的方法通过对未标注的数据中的结构范式进行学习，从而降低了对标注数据的需求，也就是说输入的数据是大部分未标注和少量标注数据，就可以逼近完全标记数据集的表现效果。[32,50,39]，这几个针对于图像情况的方法。<br>
分析后发现，他们评估算法的方式并不适用于将算法推广到实际的生产领域中，于是我们对于评估ssl算法的方式提出了一些新的看法。<br>
说的就是以前这些ssl在算法的效果上可能作弊的一些方面，如果使用这样统一的标准对算法进行评估的话，才能使得算法得到一个好的效果，此外他也提出了一些ssl在训练过程中的一些棉铃的问题：比如说假如我们把其他类别的数据，混入其中的话，那么所有这些ssl的算法的效果都会受到极大的影响。</li>
<li><del>×<a href="https://www.semanticscholar.org/paper/71a6896c98672fc9f41f48b7c10688d06d56437b" target="_blank" rel="noopener">Learning from labeled and unlabeled data with label propagation</a>
</del><br>
<del>这是一个很重要的方法，但是没想到这个竟然这么早？（math or algorithm？）（2002）（最近读的另一篇论文好像就借鉴的这个思路）<br>
将数据从标记的高密度区域向未标记的数据区域进行传播，这一篇论文的话，主要存在一些数学推导，我建议从19的那一篇新的标签传播开始阅读，通过这篇来补全需要的数学基础，如果另一边已经讲述的很完备了就不需要这篇的内容了</del></li>
</ul>
</blockquote>
<hr>
<h3 id="part2-key-words-searchingsuch-as-few-samples-etc">PART2 key words searching（such as few samples etc.）</h3>
<p><strong>limited labels on github：</strong></p>
<blockquote>
<ul>
<li><strong>※microsoft&rsquo;s work:<a href="https://github.com/microsoft/metric-transfer.pytorch" target="_blank" rel="noopener">github</a>
|<a href="https://arxiv.org/abs/1812.08781" target="_blank" rel="noopener">paper</a>
</strong><br>
i think it’ll be important one，we‘ll need to think carefully about this.seems like they have already make it great.<br>
思路上可以给我们启发：提出了一个针对few samples的通用框架（通过度度量传播来进行的label propagation方法），来解决无论是transfer、semi-supervised、few-shot这样解决的问题，并有了一个巨大的提升。<br>
将少量标记的label propagation到大量的未标注数据上，从而创建训练数据。主要贡献：用于传播的相似性度量从其他相关域转移时，这样的标签传播方法非常有效。<br>
<strong>这个算法框架可以细读一下，后续关照一下具体的思路和实现</strong></li>
</ul>
</blockquote>
<blockquote>
<ul>
<li>※The Limited Multi-Label Projection Layer:<a href="https://github.com/locuslab/lml" target="_blank" rel="noopener">github</a>
|<a href="https://arxiv.org/abs/1906.08707" target="_blank" rel="noopener">paper</a>
CVPR19 <br>
LML projection Layer 是一种几何的K类预测，用来再<strong>多类别少样本</strong>的情况下<strong>取代softmax</strong>的一个映射函数，这一篇主要是数学理论，在最后实现的话，要进行一定的参考和学习。</li>
<li>※Learning Classifiers for Target Domain with Limited or No Labels<a href="https://arxiv.org/abs/1901.09079v2" target="_blank" rel="noopener">paper</a>
ICML2019<br>
从所有的训练数据中学习一个混杂（mixture）的“原型”，然后将原型撕裂成一个个part/part-type（用attention机制来实现）、 然后通过多个part的概率组合来表示一个new instance。（use MACNN）。（即将变成低维的概率向量组成的编码=低维视觉属性LDVA）到时候找个图把这些方法全都对比一下。md花样太多了，玩晕了。</li>
<li>Hand and Face Segmentation with Deep Convolutional Networks using Limited Labelled Data(论文还没出)<a href="https://github.com/au-cvml-lab/Hand-and-Face-Segmentation-With-Limited-Data" target="_blank" rel="noopener">github</a>
</li>
<li>一些奇奇怪怪的github项目<a href="https://github.com/UdayaSameer/DeepSiameseNetwork" target="_blank" rel="noopener">github1</a>
</li>
</ul>
</blockquote>
<hr>
<p><strong>limited labels on google scholar：</strong></p>
<blockquote>
<ul>
<li>√<a href="https://dl.acm.org/citation.cfm?id=3098159" target="_blank" rel="noopener">Large Scale Sentiment Learning with Limited Labels</a>
SIGKDD2017<br>
他是通过对tweet的表情数据进行标注，建立的数据集，使用了<strong>self-learning</strong>和<strong>co-training</strong>两种WSL的方法，来对未标注的数据进行标注两种方法的具体注解我已经放在pdf上了</li>
<li><del>×[Large-Scale Video Understanding with Limited Training Labels](google it)</del><br>
<del>这尼玛是本综述的书，吓老子一跳</del></li>
</ul>
</blockquote>
<hr>
<p><strong>few samples on google scholar：</strong></p>
<blockquote>
<ul>
<li><del>×<a href="https://ieeexplore.ieee.org/abstract/document/6706969" target="_blank" rel="noopener">Learning Convolutional nerual networks from few samples</a>
2013<br>
this paper use the method of pre-trained (transfer learning instead nowadays) to get a satisfatory result.<br>
这篇文章太早了，需要的话再重新说吧。先不看</del></li>
<li><strong>※※<a href="https://arxiv.org/abs/1711.04043" target="_blank" rel="noopener">Few-Shot Learning with Graph Neural Networks</a>
</strong>（two-version）（2017）（2018ICLR）<br>
using graph network to implement semi-supervised. this research prove that the graph method perform well on &lsquo;relathinal&rsquo; tasks.<br>
定义了一种图模型的网络框架来实现few-shot等few samples的任务，表明这样的图网络架构能够很好的实现关系这样的处理，也很容易在这样的情境下进行拓展，这也是一个框架设计的任务。但是我们能够从中学习一下图模型如何针对关系网络进行学习和训练的，以及探讨一下图网络的优势。这一篇文章也探讨了度量学习和元学习的一些东西，这一篇可以给一个高的阅读优先级。</li>
</ul>
</blockquote>
<hr>
<p><strong>data programing:</strong></p>
<blockquote>
<ul>
<li>end</li>
</ul>
</blockquote>
<hr>
<p><strong>Label propagation:</strong></p>
<blockquote>
<ul>
<li>※<a href="https://link.springer.com/chapter/10.1007/978-3-642-33715-4_36" target="_blank" rel="noopener">Active Frame Selection for Label Propagation in Videos</a>
ECCV2012<br>
decide how many frames we&rsquo;ll need to mark by human for the best result .<br>
文章通过动态规划来选定视频中的k个frame，作为key frame，通过这几个frame的人工标记，能够最大的降低算法在label propagation中的标记误差，（其中num of k和误差的权衡还不是特别清楚）取代了以往这个key frame选择的随机性，带来更好的性能。<br>
此外这个方法还关注于帧数选择的动态性，由于视频的独立性，所以固定帧数的选择不一定是合适的，应该根据视频本身的特性来选择才是更好的。（但是不知道时空复杂度怎么说）<br>
值得一提的是，文中还提到了一些辅助人工标注的算法，这些算法有时间的话可以通过CSDN去调研一下。（防撞车）</li>
<li>√<a href="http://openaccess.thecvf.com/content_iccv_2013/html/Wang_Dynamic_Label_Propagation_2013_ICCV_paper.html" target="_blank" rel="noopener">Dynamic Label Propagation for Semi-Supervised Multi-class Multi-label Classification</a>
ICCV2013<br>
是一个基于图的方法，和eccv2012一致的地方在于，都认为视频任务的标注任务中，动态规划的part是需要的，上一篇用动态规划来实现keyframe的选择，这篇文章这是完全的semi-supervised的任务，他用dynamic的办法，动态的对多标签和多类信心进行拟合，从而动态的去更新相似性的度量，使用KNN来保留数据的固有结构。</li>
<li>※※<a href="https://ieeexplore.ieee.org/abstract/document/7447818" target="_blank" rel="noopener">Label Propagation via Teaching-to-Learn and Learning-to-Teach</a>
2016TNNLS<br>
一个迭代的label propagation方法，结合了一定self-learning 的机制，从dataset中迭代的选出易于分类的部分，然后通过不断的对这种易于标注的数据中去self-learning，从而提高分类器的性能，然后逐步的去针对模糊边界进行propagate。感觉是一个好方法<br>
intro中简要的对比介绍了这之前的一些label propagation方法，包括DLP。
based on the sota LPmethod，所以之前的一些可能可以不用看了，</li>
<li>※※※<a href="https://arxiv.org/abs/1805.10002" target="_blank" rel="noopener">Learning to Propagate Labels: Transductive Propagation Network for Few-shot Learning</a>
ICLR2019<br>
结合了meta-learning/label propagation/transductive inference的方法，细看细看，这一篇一定要细看。太强了兄弟。intro里面也包含了很多的东西。</li>
</ul>
</blockquote>
<hr>
<h3 id="part3-few-shot-learning--etcincluding-one-shot-learning">PART3 few-shot learning  etc.（including one-shot learning)</h3>
<p>淦淦淦，这尼玛比的定义能不能统一一哈</p>
<p><strong>Few-Shot Learning:</strong></p>
<blockquote>
<ul>
<li>√<a href="http://papers.nips.cc/paper/6996-prototypical-networks-for-few-shot-learning" target="_blank" rel="noopener">Prototypical Networks for Few-shot Learning</a>
2017\NIPS<br>
思路上好像和19年的cvpr那片有点像，先学习一个overall 再通过度量空间对newdata进行适应性的分配和训练。通过intro，我认为更像是一个简单的embedding的办法，将sample聚集到embedding space的一个原型上，在对其进行近邻标签传播算法把。<br>
但是里面有一些数学推导，可能是关于距离的，在我们后续需要划分指标的时候可以来看看这篇到底说了啥。（原型网络的数学推导。）</li>
<li>√<a href="https://arxiv.org/abs/1803.00676" target="_blank" rel="noopener">Meta-Learning for Semi-Supervised Few-Shot Classification</a>
2018、ICLR<br>
正好是上面那片原型网络的升级方法，这也太巧了把。重开一个新的课题，设置环境成为一个wild的环境，存在干扰项，将未标注的data也混杂进原型的训练中。</li>
<li><del>×<a href="https://openreview.net/forum?id=SkMjFKJwG" target="_blank" rel="noopener">Conditional Networks for Few-Shot Semantic Segmentation</a>
2018\ICLRworkshop track<br>
貌似有点弟弟，没提出什么有用的东西</del></li>
<li>※<a href="http://openaccess.thecvf.com/content_ICCV_2019/html/Kang_Few-Shot_Object_Detection_via_Feature_Reweighting_ICCV_2019_paper.html" target="_blank" rel="noopener">Few-Shot Object Detection via Feature Reweighting</a>
2019/ICCV<br>
在一个base class 的dataset上进行meta training，然后通过 reweighting 操作，adapt to novel classes。<br>
global原型，meta的场景学习策略，transfer的reweighting操作，以及在few-shot问题种加入了很多算法并没有考虑的localization问题。<br>
这篇论文看起来还行。</li>
<li>※※<a href="http://openaccess.thecvf.com/content_CVPR_2019/html/Sun_Meta-Transfer_Learning_for_Few-Shot_Learning_CVPR_2019_paper.html" target="_blank" rel="noopener">Meta-Transfer Learning for Few-Shot Learning</a>
2019\CVPR<br>
通过多次的meta学习，来找到参数相对于原DNN网络（普通的meta都是用的浅层网络）而言的scaling和shifting，感觉和上一篇reweighting方法存在一定的相似性。 同时我们也知道基本的meta-learning 方法和场景图应用的方法存在极大的相似性。
此外在训练策略上，采用了一个HTmini-batch的变体策略。（figure1有简要说明，结合后面的策略观看）</li>
<li><del>×<a href="http://104.211.88.42:8080/handle/2005/4275" target="_blank" rel="noopener">Deep Learning Models for Few-shot and Metric Learning</a>
<br>
这一篇看不了</del></li>
<li>√<a href="http://openaccess.thecvf.com/content_cvpr_2018/html/Sung_Learning_to_Compare_CVPR_2018_paper.html" target="_blank" rel="noopener">Learning to Compare: Relation Network for Few-Shot Learning</a>
2018\CVPR<br>
meta-learning 中的query 和support 不要搞混了。<br>
（前面还有一步是通过embedding来学习一个合适的feature）<br>
感觉上是一个基础的meta-learning框架，通过训练过程中对metric distance的学习，得到一个模型框架，然后通过模型将support data在metric space中与query data进行distance的衡量，从中选择shortest one作为classification的指标。</li>
<li>※<a href="http://openaccess.thecvf.com/content_cvpr_2018/html/Gidaris_Dynamic_Few-Shot_Visual_CVPR_2018_paper.html" target="_blank" rel="noopener">Dynamic Few-Shot Visual Learning Without Forgetting</a>
2018\CVPR<br>
为了使得模型在学习新的类别的时候，对旧的类别的识别能力依旧能保留下来，提出了两个策略，一个是基于attention 的分类权重生成器，二是对ConvNet进行重新设计，使其提取出feature的表征向量和分类权重向量之间的余弦相似性。？具体的还没看。但我认为主要努力的方向好像不是很对。</li>
<li><a href="http://openaccess.thecvf.com/content_ECCV_2018/html/Liangyan_Gui_Few-Shot_Human_Motion_ECCV_2018_paper.html" target="_blank" rel="noopener">Few-Shot Human Motion Prediction via Meta-Learning</a>
2018\CVPR<br>
是一种结合了MAML、MRN、Meta-Learning的策略，本质还是一个few-shot的工作，没有提到怎么把这样的工作适应到真实的应用上，<br>
这一篇论文非常需要机器详细的阅读，不然的话不知道他到底是怎么操作的。</li>
</ul>
</blockquote>
<p>最终我们可以提出一个framework，通过对弱监督方法的嵌入，使得标注的任务变成一个人机交互的loop，通过我们对算法的干预，他将从标签的概率预测变成一个确定的指标预测，然后执行self-learning的方法，让自己逐渐变得更好，设定一个drop out，可以计算一个算法的最终所求时间。</p>

  </div>
</div>

<script>
    


function sanitizeContent(content) {
    
    return content.replace(/[\x00-\x1F\x7F]/g, '').trim(); 
}

function encryptContent(password, content) {
    const key = CryptoJS.MD5(password).toString();
    const iv = key.substring(16); 
    const paddedContent = padContent(content);
    const encrypted = CryptoJS.AES.encrypt(paddedContent, CryptoJS.enc.Utf8.parse(key), {
        iv: CryptoJS.enc.Utf8.parse(iv),
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
}

function padContent(content) {
    const blockSize = 32; 
    const padlen = blockSize - (content.length % blockSize);
    
    
    return content;
}

function processEncryptedBlocks() {
    const blocks = document.querySelectorAll('.hugo-encryptor-cipher-text');
    blocks.forEach(block => {
        const password = block.getAttribute('data-password');
        const content = block.innerHTML.trim(); 
        const sanitizedContent = sanitizeContent(content); 
        const encryptedContent = encryptContent(password, sanitizedContent);
        block.innerHTML = encryptedContent;
        block.removeAttribute('data-password');
    });

    
    const script = document.createElement('script');
    script.src = '/js/decrypt.js';
    document.body.appendChild(script);
}


document.addEventListener('DOMContentLoaded', processEncryptedBlocks);
</script>
]]></content:encoded>
    </item>
    <item>
      <title>IL-MgSvF</title>
      <link>https://aikenh.cn/posts/il-mgsvf/</link>
      <pubDate>Mon, 29 Nov 2021 13:12:05 +0000</pubDate>
      <guid>https://aikenh.cn/posts/il-mgsvf/</guid>
      <description>Multi-Grained Slow vs. Fast Framework for Few-Shot Class-Incremental Learning</description>
      <content:encoded><![CDATA[<p>@Author &amp; Paper：<a href="https://arxiv.org/pdf/2006.15524.pdf" target="_blank" rel="noopener">Arxiv</a>

@Note：Aikenhong 2021/11/12</p>
<p><a href="https://blog.csdn.net/cp_oldy/article/details/111714896" target="_blank" rel="noopener">Other’s Note 1 </a>
</p>
<h2 id="intro">Intro</h2>
<p><strong>旧知识的缓慢忘记和新知识的快速适应的困境</strong>：主要探讨Incremental中的Old和New的相互牵制和适应的问题，</p>
<p>旧知识的缓慢遗忘会导致对新任务的欠拟合，而快速适应会导致灾难性的遗忘，如何对这两种策略之间进行权衡，是一个重要的问题。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211112114701.png">
    <img alt="image-20211112110043089" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211112114701.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211112114701.png" style="display: block; margin: 0 auto;"
      alt="image-20211112110043089"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><strong>多尺度混合</strong>的解决这个问题：</p>
<ul>
<li>Intra-space： 新类别的特征在同一个特征空间中</li>
<li>inter-saoce：新旧类别的特征在不同的特征空间中</li>
</ul>
<p>本文提出的<strong>多粒度策略</strong>：</p>
<ol>
<li>提出了一种频率感知的正则化操作，加速空间内的增量学习能力</li>
<li>新的特征空间组合操作，提升空间间的学习性能</li>
</ol>
<blockquote>
<p>实际上新类和旧类的特征最好是通过自监督或者无监督的特征学习方法归化到同一个特征空间中，在这种情况下对Classifier进行调整可能是一种更好的策略。通过混合特征空间来得到一个泛化能力更高的特征表示器。</p>
<p>传统的策略：无论是累加还是进行数据混合进行梯度计算，这种方式应该是将类别之间的梯度进行直接的叠加。</p>
<ul>
<li>是否可以自行混合不同类别之间的学习梯度？通过对梯度的下降方程求解来得到一个旧类和新类之间的更好的下降方法。</li>
<li>具体的操作上就是对step进行处理，通过mixdataset对梯度进行分开计算</li>
<li>在混合策略上可以考虑梯度的下降方向，对不同的维度进行加权计算？</li>
<li>上述的策略难以实施的点在于框架中的梯度是自动计算的，我们可以对损失进行加权，但是很难重新计算不同节点之间的梯度值</li>
<li>退而求其次的方法就是对新旧类的损失进行加权处理, 或者直接的混合数据</li>
<li>如果我们能获取梯度的方向, 或许我们能在每次迭代的过程中获得一个更好的加权值</li>
<li>首先可以尝试对梯度进行获取,<a href="https://zhuanlan.zhihu.com/p/168443176" target="_blank" rel="noopener">Grad</a>
</li>
<li>我们在蒸馏的过程中通过MLP对不同的类别进行聚类划分, 这种方式的聚类和传统机器学习聚类的优劣又如何对比解释呢.</li>
<li>能不能用PCA方法或者multi-head策略来对特征进行处理, 这种类似因果的方式来分析特征中的<strong>冗余维度</strong></li>
<li>上述的分析基于Mix Guide make error 的想法, 实际上还有一个问题就是Feature’s capabliity 不足的问题</li>
</ul>
</blockquote>
<p>New Key Word： Few-Shot class-incremental Learning</p>
<p>有大规模训练样本的第一个任务和具有有限样本的新类学习两阶段任务的这种场景</p>
<h2 id="related-work">Related Work</h2>
<ul>
<li>框架策略:</li>
<li>复习策略</li>
<li>正则化策略</li>
</ul>
<h2 id="main">Main</h2>
<p>该文认为统一的特征空间是相互关联的，很难相互解开进行svf分析，同时新知识和旧知识的学习方向通常而言不一致，甚至有时是相互矛盾的，所以他认为需要一个全新的特征空间。</p>
<blockquote>
<p>但是在Few-Shot的情境下，新的特征空间的泛化能力可能很差，本身带来的准确率就很有问题把</p>
</blockquote>
<p>使用离散余弦变化，建立一个空间内的SVF特征分解方案，实现了一个像互不相关的正交频率空间，同时在不同频率上对新旧两种知识的重要性不同，低频分量对于保存旧知识的贡献更大，遗忘率则随着频率的增加而增加。</p>
<p>所以逼近旧特征空间的低频分量的正则项权重更高, 具体而言就是独立的特征空间的更新比其他空间更新更慢, 通过对特征空间的组合来组成上述空间的方法, 是十分灵活的, 即使是简单的串联也能带来巨大的性能提高</p>
<blockquote>
<p>这确实是我没想到的, 也就是如果我们使特征并行化, 对最终准确率的提升增益是更大的, 这是为何.</p>
</blockquote>
<h2 id="framework">FrameWork</h2>
<p>实际上就是维护两个模型, 然后进行特征的串联, 进行分类. 每次只对新的数据进行训练, 不会使用旧的数据.</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211112111714.png">
    <img alt="image-20211112111713507" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211112111714.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211112111714.png" style="display: block; margin: 0 auto;"
      alt="image-20211112111713507"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
]]></content:encoded>
    </item>
    <item>
      <title>SSL-MoCov3</title>
      <link>https://aikenh.cn/posts/ssl-mocov3/</link>
      <pubDate>Mon, 29 Nov 2021 13:12:05 +0000</pubDate>
      <guid>https://aikenh.cn/posts/ssl-mocov3/</guid>
      <description>MoCo V3 An Empirical Study of Training Self-Supervised Visual Transformers</description>
      <content:encoded><![CDATA[<p>@Aiken 2021</p>
<p>恺明大神对自监督学习+transformer的实证研究，针对Transformer再自监督学习学习框架中的训练不稳定问题提出了<strong>Random Patch Projection</strong>的解决方案。</p>
<p><a href="https://mp.weixin.qq.com/s/waqkJkwqxU-7utfNnwr2Gg" target="_blank" rel="noopener">Article</a>
；<a href="https://arxiv.org/abs/2104.02057" target="_blank" rel="noopener">Paper</a>
；</p>
<h2 id="motivation">Motivation</h2>
<p>ViT的方法在自监督学习的任务中，精度下降的主要原因是由于算法的不稳定性，容易陷入局部的最优值，本文主要聚焦于<strong>采用视觉领域的自监督框架进行Transformer的训练</strong>，CNN的训练方法已经是一个比较明确约定俗称的方法，而Transformer的训练架构实际上还没有被完全的构建。</p>
]]></content:encoded>
    </item>
    <item>
      <title>Survey for Few-Shot Learning</title>
      <link>https://aikenh.cn/posts/fsl-collection/</link>
      <pubDate>Mon, 29 Nov 2021 13:12:05 +0000</pubDate>
      <guid>https://aikenh.cn/posts/fsl-collection/</guid>
      <description>&lt;p&gt;@aikenhong 2020
@h.aiken.970@gmail.com&lt;/p&gt;
&lt;p&gt;另一个综述文章：https://zhuanlan.zhihu.com/p/61215293
对该文中一些内容有一些补充，可以看看&lt;/p&gt;
&lt;p&gt;FSL简介：https://blog.csdn.net/xhw205/article/details/79491649&lt;/p&gt;
&lt;p&gt;GCN用于FSL：https://blog.csdn.net/qq_36022260/article/details/93753532&lt;/p&gt;
&lt;h2 id=&#34;abstract&#34;&gt;Abstract&lt;/h2&gt;
&lt;p&gt;FSL的根本目的就是弥合人工智能和人类之间的鸿沟，从少量带有监督信息的示例中学习。像人类一样有很高的泛化能力。这也能解决在实际应用场景中，数据难以收集或者大型数据难以建立的情景。&lt;/p&gt;
&lt;p&gt;FSL的&lt;strong&gt;核心问题&lt;/strong&gt;是：经验风险最小化器不可靠；那么如何&lt;strong&gt;使用先验知识&lt;/strong&gt;去解决这个问题？&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;现阶段针对FSL提出的一些相关的机器学习方法：
&lt;code&gt;meta-learning;&lt;/code&gt; &lt;code&gt;embedding learning;&lt;/code&gt;  &lt;code&gt;generative modeling etc.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;本文的主要工作：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;基于FSL的原有设定，在现阶段的FSL发展上给出正式定义，同时阐明具体目标以及解决方式&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过具体示例列举和FSL的相关学习问题，比较了相关性和差异性，更好的区分问题&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;指出核心问题：经验风险最小化器不可靠，这提供了更系统有组织的改进FSL的方向。
经验风险最小化器👉：基于ML中的错误分解来分析的&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;/ol&gt;
&lt;h2 id=&#34;notation-and-terminology&#34;&gt;Notation and Terminology&lt;/h2&gt;
&lt;p&gt;
&lt;div class=&#34;post-img-view&#34;&gt;
  &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200519154522883.png&#34;&gt;
    &lt;img alt=&#34; &#34; loading=&#34;lazy&#34; src=&#34;https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200519154522883.png&#34;class=&#34;responsive-image&#34; src=&#34;https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200519154522883.png&#34; style=&#34;display: block; margin: 0 auto;&#34;
      alt=&#34; &#34;  /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;script&gt;
  document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
      var images = document.querySelectorAll(&#34;.responsive-image&#34;);
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + &#34;px&#34;;
      });
  });
&lt;/script&gt;

一般基于参数方法（因为非参数方法需要大量数据），在假设空间中搜索最优假设，并基于基于标签的Loss Function 来衡量效果。&lt;/p&gt;
&lt;h2 id=&#34;main-body&#34;&gt;Main Body&lt;/h2&gt;
&lt;h3 id=&#34;overview&#34;&gt;Overview&lt;/h3&gt;
&lt;p&gt;2.1：具体定义&amp;amp;示例 2.2：相关问题和FSL的相关性和差异 2.3：核心问题 2.4:现有的方法如何处理这个问题&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>@aikenhong 2020
@h.aiken.970@gmail.com</p>
<p>另一个综述文章：https://zhuanlan.zhihu.com/p/61215293
对该文中一些内容有一些补充，可以看看</p>
<p>FSL简介：https://blog.csdn.net/xhw205/article/details/79491649</p>
<p>GCN用于FSL：https://blog.csdn.net/qq_36022260/article/details/93753532</p>
<h2 id="abstract">Abstract</h2>
<p>FSL的根本目的就是弥合人工智能和人类之间的鸿沟，从少量带有监督信息的示例中学习。像人类一样有很高的泛化能力。这也能解决在实际应用场景中，数据难以收集或者大型数据难以建立的情景。</p>
<p>FSL的<strong>核心问题</strong>是：经验风险最小化器不可靠；那么如何<strong>使用先验知识</strong>去解决这个问题？</p>
<p>三个主要的角度：</p>
<ol>
<li>数据：使用先验知识增强数据的监督经验</li>
<li>模型：使用先验知识来降低假设空间</li>
<li>算法：使用先验知识来改变搜索最佳假设（来进行搜索？)</li>
</ol>
<p>现阶段针对FSL提出的一些相关的机器学习方法：
<code>meta-learning;</code> <code>embedding learning;</code>  <code>generative modeling etc.</code></p>
<p><strong>本文的主要工作：</strong></p>
<ol>
<li>
<p>基于FSL的原有设定，在现阶段的FSL发展上给出正式定义，同时阐明具体目标以及解决方式</p>
</li>
<li>
<p>通过具体示例列举和FSL的相关学习问题，比较了相关性和差异性，更好的区分问题</p>
</li>
<li>
<p>指出核心问题：经验风险最小化器不可靠，这提供了更系统有组织的改进FSL的方向。
经验风险最小化器👉：基于ML中的错误分解来分析的</p>
</li>
<li>
<p>整理，更好的理解</p>
</li>
<li>
<p>未来方向</p>
</li>
</ol>
<h2 id="notation-and-terminology">Notation and Terminology</h2>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200519154522883.png">
    <img alt=" " loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200519154522883.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200519154522883.png" style="display: block; margin: 0 auto;"
      alt=" "  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>

一般基于参数方法（因为非参数方法需要大量数据），在假设空间中搜索最优假设，并基于基于标签的Loss Function 来衡量效果。</p>
<h2 id="main-body">Main Body</h2>
<h3 id="overview">Overview</h3>
<p>2.1：具体定义&amp;示例 2.2：相关问题和FSL的相关性和差异 2.3：核心问题 2.4:现有的方法如何处理这个问题</p>
<h4 id="definition">Definition</h4>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200519160715974.png">
    <img alt="image-20200519160715974" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200519160715974.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200519160715974.png" style="display: block; margin: 0 auto;"
      alt="image-20200519160715974"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><strong>基本定义</strong>：FSL是一类机器学习（由E，T，P定义），其中E只包含有限数量的带有目标T监管信息的示例。</p>
<p>**研究方法：**通常使用N-way K-shot的分类研究方法：从少量类别中的少量样本回归出ML模型，</p>
<p>​								Training Set Contains：KN examples.</p>
<p><strong>Typical scenarios of FSL:</strong></p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200519165647756.png">
    <img alt="image-20200519165647756" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200519165647756.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200519165647756.png" style="display: block; margin: 0 auto;"
      alt="image-20200519165647756"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ul>
<li>Reducing data gathering effort and computational cost:
“raw images of other classes or pre-trained models ”
似乎有点迁移学习的味道了，改善从已有的类似数据集过来的model？</li>
<li>Learning for rare cases</li>
<li>Acting as a test bed for learning like human.</li>
</ul>
<p>和普通的ML的应用最明显的<strong>区别</strong>就是E中prior knowledge的应用，将T和先验知识结合起来。（such as Bayesian Learning [35,76]）</p>
<p>**Attention：**Zero-shot：要求E中需要包含其他模态的信息（比如属性，wordnet，word embedding之类的）</p>
<h4 id="relevant-learning-problems">Relevant Learning Problems</h4>
<ul>
<li>
<p><strong>WSL:Weakly supervised learning:</strong>
重点在于learns from E containing only Weak supervised（such as： 不完全，不精确，不准确，或者充满噪声的监督信息），WS 中信息不完全只有少样本这一类情况就是FSL了，在此基础上基于Oracle还是人工干预的方法，可以进一步细分为：</p>
</li>
<li>
<p><strong>Semi-supervised learning：</strong>
从E中的少量标记样本和大量未标记样本中学习。示例：文本和网页分类；其中包含Positive-unlabeled learning这种特殊问题，只包含positive label的问题：具体而言就是，只知道用户现在用户中标记的好友，而与其他未标记人之间的关系是未知的。</p>
</li>
<li>
<p><strong>Active Learning：</strong>
文章：选择信息量最大的未标记数据区query an ordacle？
个人理解：选择信息量最大（通常用不确定性大的数据表示）来让人标注，从而构建数据集，让算法能够通过较少的数据标注操作实现更好的效果。</p>
<p>WSL with incomplete supervision 仅仅包括分类和回归的内容，而FSL还包含RL问题；WSL使用unlabel data 对E进行扩充，而FSL更多的使用各种类型的prior knowledge来扩充E，包括pre-train model ，其他领域的监督数据，未标记数据等等。</p>
</li>
</ul>
<hr>
<ul>
<li>
<p><strong>Imbalance learning：</strong></p>
<p>数据集的分布不均衡，比如一些y值很少用到的情况。IL从所有可能的y中Train&amp;test，FSL基于少量案例train&amp;test y，同时也可能基于一些先验知识来。</p>
</li>
<li>
<p><strong>Transfer learning：</strong></p>
<p>transfers knowledge from the source domain/task 👉 target domain/task, where training data is scarce.其中<strong>Domin adaptation</strong>，是一种TL：source/target <strong>tasks</strong> are the same but the source/target <strong>domains</strong> are different.举例说明就是：情感识别，一个基于电影评论，一个基于日用品评论。
Transfer Learning广泛的应用于FSL，[7,82,85]将先验知识从源任务转移到Few-shot task，从一些训练数据丰富的源域转移</p>
</li>
<li>
<p>**Meta-learning：**感觉正文中讲的是个狗屎，后续通过附录中的看看</p>
<p>Meta-learning methods can be used to deal with the FSL problem. the meta-learner is taken as prior knowledge to guide each specific FSL task.</p>
</li>
</ul>
<h4 id="core-issue">Core Issue</h4>
<ul>
<li>经验风险最小化
Machine Learning其实是一个经验风险最小化的模型</li>
</ul>
<div>
$$ 
R(h)=\int \ell(h(x), y) d p(x, y)=\mathbb{E}[\ell(h(x), y)] \\
 $$
</div>
<div>
$$ 
R_{I}(h)=\frac{1}{I} \sum_{i=1}^{I} \ell\left(h\left(x_{i}\right), y_{i}\right)\\
 $$
</div>
<div>
$$ 
\mathbb{E}\left[R\left(h_{I}\right)-R(\hat{h})\right]=\underbrace{\mathbb{E}\left[R\left(h^{*}\right)-R(\hat{h})\right]}_{\mathcal{E}_{\mathrm{app}}(\mathcal{H})}+\underbrace{\mathbb{E}\left[R\left(h_{I}\right)-R\left(h^{*}\right)\right]}_{\mathcal{S}_{\mathrm{est}}(\mathcal{H}, I)}
 $$
</div>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520155345136.png">
    <img alt="image-20200520155345136" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520155345136.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520155345136.png" style="display: block; margin: 0 auto;"
      alt="image-20200520155345136"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>上面这1 3的区别一个是在全空间上，另一个是在是我们的假设空间中，能取到的最优解。</p>
<p>总体误差可以基于最小预期风险和最小经验风险来表示，如等式3。期望实和训练集的随机选择有关的，the approximation error 衡量了假设空间中的函数能够接近最优假设的程度，the estimation error 衡量了，最小经验误差代替最小期望误差在假设空间内的影响。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520154733872.png">
    <img alt="image-20200520154733872" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520154733872.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520154733872.png" style="display: block; margin: 0 auto;"
      alt="image-20200520154733872"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ul>
<li>
<p>data （which provides Dtrain）数据角度</p>
</li>
<li>
<p>model which determines H（embedding function，转换到假设空间）</p>
</li>
<li>
<p>algorithm（searches for the optimal h）学习算法，下降方向</p>
</li>
<li>
<p>不可靠的经验风险最小化</p>
<p>如果数据足够大的话，通过少量样本计算出来的假设空间就可以逼近实际上的最优假设空间，也就能得到一个很好的近似，但是在FSL中，可用的样本数很少，所以可能没办法产生很好的逼近，在这种情况下，产生的<strong>经验风险最小化指标hl过拟合</strong>，这就是FSL中的核心问题。</p>
</li>
</ul>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520155719041.png">
    <img alt="image-20200520155719041" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520155719041.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520155719041.png" style="display: block; margin: 0 auto;"
      alt="image-20200520155719041"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h4 id="taxonomy">Taxonomy</h4>
<p>为了解决FSL问题中经验风险最小化工具中hl的问题，prior knowledge是至关重要的，利用先验知识来扩充信息量的不足，基于先验知识的类别和使用方式就能对FSL works进行分类。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520161249706.png">
    <img alt="image-20200520161249706" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520161249706.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520161249706.png" style="display: block; margin: 0 auto;"
      alt="image-20200520161249706"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ul>
<li>Data：通过数据增强等方式，增加数据量，从而使得经验风险最小化因子能够更加的准确。</li>
<li>Model：用先验知识来约束假设空间，使得需要搜索的范围变小，那么基于较少的数据也能够得到一个较好的估计，（相比原来）</li>
<li>Algorithm：使用先验知识，来搜索最优假设的参数，基于这些先验知识提供一个较好的initialization，或者guiding the searching steps</li>
</ul>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520164955304.png">
    <img alt="image-20200520164955304" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520164955304.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520164955304.png" style="display: block; margin: 0 auto;"
      alt="image-20200520164955304"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="data">Data</h3>
<p><strong>通过手工指定规则</strong>来进行数据增强的方式例如：:arrow_double_down: 很大程度上取决于领域的知识也需要人工成本，此外，这样的方式在数据集间的泛化能力很差，一般都是针对性设计，而且这样的不变性，不可能由人工穷举出来，所以这样的方式不能完全解决FSL问题。</p>
<blockquote>
<p>translation, flipping, shearing, scaling, reflection, cropping, rotation.</p>
</blockquote>
<p><strong>Advance data augmentation:</strong></p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520193608911.png">
    <img alt="image-20200520193608911" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520193608911.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520193608911.png" style="display: block; margin: 0 auto;"
      alt="image-20200520193608911"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h4 id="transforming-samples-from-dtrain">Transforming Samples from Dtrain</h4>
<ol>
<li>
<p>对训练集的数据进行几何<strong>变化处理</strong>，生成其他的样本，构建一个更大的数据集。</p>
</li>
<li>
<p>从相似类中学习一组编码器（每个编码器代表一个<strong>类内可变性</strong>），将这些习得的变化量添加到样本中形成新的样本。</p>
</li>
<li>
<p>基于差异从其他类别中转移过来</p>
</li>
<li>
<p>从一个样本变成多个；连续属性子空间来添加属性变化</p>
</li>
</ol>
<p>基本思路是一致的，通过变换，在原本数据的基础上，构建新的数据，只是有着不同的构建方式。详细的各种类型的构建可以看参考文献。</p>
<h4 id="transforming-samples-from-a-weakly-labeled-or-unlabeled-data-set">Transforming Samples from a Weakly Labeled or Unlabeled Data Set</h4>
<p>基于弱标签或者无标签的数据来进行数据增强的情况，<strong>类似视频</strong>中有些事件之间变化比较大的情况，可以将这样的数据添加到训练集中来更清楚的预测。</p>
<p>:dagger:但是如何筛选哪些有需要的弱监督数据？</p>
<p>⭐基于训练数据训练一个svm进行筛选，然后将具有目标的示例添加进数据集</p>
<p>⭐Label Propagation,直接使用未标记的数据集</p>
<p>⭐也有文章采取逐步从信息量最大的数据中筛选的做法</p>
<h4 id="transforming-samples-from-similar-data-sets">Transforming Samples from Similar Data Sets</h4>
<p>:tada: 汇总和改造相似的数据集，来扩充Few shot情况，基于样本之间的相似性度量来确立权重，典型的方法就是：使用GAN，生成器将Few-shot的训练集映射到大规模数据集，另一个生成器将大规模数据集的样本映射过来，从而训练出可以辅助样本迁移的模型。</p>
<h4 id="summary1">Summary1</h4>
<p>这些方法的使用取决于具体任务；</p>
<p>:x: 缺点：通常是针对数据集量身定做的</p>
<p>:+1: 针对这个问题有人提出了AutoAugment</p>
<p>:heavy_multiplication_x: 缺点：文本和音频的情况下就很难做这样的生成了</p>
<h3 id="model">MODEL</h3>
<p>:fire: 如果仅仅基于简单的假设去考虑的话，那么可能在我们的假设空间中的最优和实际的最优(不足以模拟现实社会中的复杂问题)会有比较大的距离，但是如果考虑复杂多样的假设空间，那么标准的机器学习模型也是不可行的（数据量不足以优化到最优解），考虑使用先验知识，将复杂多样的假设空间H 约束到较小的情况下进行学习，这样的话经验风险最小化器将会更加的可靠，同时也降低了过拟合的可能性。</p>
<p>根据先验知识的类型，可以划分成如下几种FSL：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520212452504.png">
    <img alt="image-20200520212452504" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520212452504.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520212452504.png" style="display: block; margin: 0 auto;"
      alt="image-20200520212452504"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h4 id="multitask-learning">Multitask Learning</h4>
<p>:fire: 多个相关任务协同训练，基于特定任务的信息和通用任务的信息来一起学习，其中利用某些/其他任务的大量数据（源任务），在训练过程中，通过学习到的参数来对只有Few-shot（target task）进行约束。基于训练中参数对target的约束方式可以分为</p>
<ul>
<li>
<p><strong>parameter sharing参数共享</strong> 160 61 95 12
基本的网络架构如下图</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520232155796.png">
    <img alt="image-20200520232155796" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520232155796.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520232155796.png" style="display: block; margin: 0 auto;"
      alt="image-20200520232155796"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>

:zero: 有多种不同的架构，整体都是由共享层（参数是一致的）和特定于任务的层一起构建的，简单的描述一下如下：</p>
<ol>
<li>初始共享然后分配到特定任务；2. 源任务（pre训练）训练共享层，目标任务训练目标层；3.分别单独学习再有共享的编码器嵌入成一体。</li>
</ol>
</li>
<li>
<p><strong>parameter tying参数绑定</strong> 45 151 85

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520232612155.png">
    <img alt="image-20200520232612155" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520232612155.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200520232612155.png" style="display: block; margin: 0 auto;"
      alt="image-20200520232612155"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>

⭐基本思路：鼓励不同任务之间的参数存在相似性。对参数进行正则化是一种流行的方法。</p>
<p>:one: 有的方法对<strong>成对参数之间的差异</strong>及逆行了惩罚，从而确保参数分布的相似性</p>
<p>:two: 有的方法通过针对源任务和目标任务设置不同的CNN，之间使用特殊的正则化术语对齐。</p>
</li>
</ul>
<h4 id="embedding-learning">Embedding Learning</h4>
<p>基于先验知识（同时可以额外使用Dtrain中的任务特定信息）构建样本的一个低维嵌入，这样便能得到一个较小的假设空间，同时相似的样本会紧密接近，而异类的样本更容易区分。</p>
<p><strong>Key Components：</strong></p>
<ol>
<li>将测试，训练样本用embedding函数（f，g）嵌入。f，g可以统一，但是分离的时候可以受获更好的准确度</li>
<li>相似性度量在嵌入空间（一般都是维度更低的空间）进行，</li>
</ol>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200521000708513.png">
    <img alt="image-20200521000708513" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200521000708513.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200521000708513.png" style="display: block; margin: 0 auto;"
      alt="image-20200521000708513"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><strong>可以根据embedding函数的参数是否随任务变化分类</strong></p>
<ol>
<li>
<p>针对任务的嵌入模型
仅仅使用来自该任务的信息来学习针对性的嵌入模型。</p>
</li>
<li>
<p>通用的嵌入模型（task-invariant）
使用有足够样本且具有各种输出的大规模数据集，学习通用的embedding function，然后直接用于Fewshot。Recently, more complicated embeddings are learned [70, 150] by a <strong>convolutional siamese net</strong> [20]

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200521122115448.png">
    <img alt="image-20200521122115448" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200521122115448.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200521122115448.png" style="display: block; margin: 0 auto;"
      alt="image-20200521122115448"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>通常而言，task-invariant不会使用Few-shot的数据集来更新embedding function参数，但是，其中很多情景都会模拟few-shot 的情景来训练embedding从而确保对此类任务有更好的概括性能。</p>
<p>⭐<strong>Mathching Nets</strong>
meta-learning / resLSTM / AL /set-to-set</p>
<p>⭐<strong>Prototypical Networks</strong></p>
<p>​		embedding(xtest)不与每个g(xi)对比，而是每一类别的训练数据都有一个”原型“（原型公式如下），与原型对比，减少计算量。有两种变体：应用到matching-net 和 semi-supervised-108（软分配未标注的样本用以增强Dtrain）</p>
</li>
</ol>
<div>
$$ 
   c_{n}=\frac{1}{K} \sum_{i=1}^{K} g\left(x_{i}\right)c_{n}=\frac{1}{K} \sum_{i=1}^{K} g\left(x_{i}\right)
   $$
</div>
<p>:zap:<strong>Other Method</strong></p>
<p>​		ARC：利用attention+LSTM将xtest的不同区域和原型进行比较，然后将比较结果作为中间嵌入，在使用biLSTM（双向LSTM）进行最终嵌入；
​		Relation Net 使用CNN将Xtest和Xi拼接在一起，再使用另一个CNN输出相似度得分。
​		GNN：利用GNN使用临近节点的信息
​		SNAIL简单神经注意力学习器（RL通常看重时间信息）：temporal convolution +Attention，聚合临近步长和通过Attention选择特定时间步长的信息。</p>
<ol start="3">
<li>
<p>混合嵌入模型，可以编码 task-specific 和 task-invariant 的信息
虽然task-invariant可以再迁移的时候减少计算成本，但是针对一些特殊的少样本情况，他是无法直接适应的，比如说原本就是小概率事件（异常），这种情况下，基于Dtrain训练的先验知识来adapt通用的embedding模型，从而组成一个混合的结构，如下图所示。</p>
<p>​	
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200521144018844.png">
    <img alt="image-20200521144018844" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200521144018844.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200521144018844.png" style="display: block; margin: 0 auto;"
      alt="image-20200521144018844"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>Learnet从多个meta-training set中学习meta-learner，并将训练实例映射成网络中的参数（convolutional Siamese net），这样f的参数就会随着输入改变。还有一些针对其的改进</p>
<p>TADAM：将类别原型平均化到嵌入中，并使用meta-learned 映射成圆形网络的参数</p>
<p>DCCN：使用固定的滤波器，并从Dtrain中学习组合系数。</p>
</li>
</ol>
<h4 id="learning-with-external-memory">Learning with External Memory</h4>
<p>基于Dtrain 训练一个Embedding function，提取出 key-value的知识，存储在外部存储器中，对于新样本（test），用Embedding&amp;相似度函数查询最相似的slots，用这些slots的组合来表示样本，然后用简单的分类器（like softmax）进行分类预测。由于对M操作成本高，所以M通常尺寸较小。当M未满时，可以讲新样本写如空闲的存储插槽。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200521150103355.png">
    <img alt="image-20200521150103355" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200521150103355.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200521150103355.png" style="display: block; margin: 0 auto;"
      alt="image-20200521150103355"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200521151204794.png">
    <img alt="image-20200521151204794" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200521151204794.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200521151204794.png" style="display: block; margin: 0 auto;"
      alt="image-20200521151204794"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>

key-value的表征，也就是memory中的定义在这个方法中至关重要，它决定了键值对对test的表征水平。根据存储器的功能，将这类方法分成两种类型：</p>
<p>:one:Refining Representations:</p>
<ul>
<li><strong>MANN</strong>：meta-learns embedding f，将同类的样本映射到同一个value，同一类的样本一起在内存中优化类表示。可以看成ProtoNet中精致的类原型。</li>
<li>当且仅当M不能很好的表征x的时候更新M。</li>
<li><strong>The Abstract Memory：</strong> 使用两个M，一个基于大量数据训练出的固定键值对，另一个从固定键值对对少量类进行精炼提取。为此有的方法会注意保留M中的FS。</li>
<li>few-shot在M中很容易被其他samples的值表征从而取代，为了解决这个问题，提出的此算法👇</li>
<li>**lifelong memory：**通过删除oldest slot来update M，同时给所有slot的期限置为0，当新样本在经过M后输出的表征与实际输出匹配的时候，就合并，而不更新M。（但是还是没有真正的解决这个问题）</li>
</ul>
<p>:two:Refining Parameters:</p>
<ul>
<li><strong>MetaNet、MN-Net：</strong> 对特定任务的数据进行fast 学习，而通用任务slow更新，然后结合memory的机制。（参数化学习</li>
</ul>
<h4 id="generative-modeling">Generative Modeling</h4>
<p>借助先验知识，从x的分布中估计先验p(x； $\theta$ )的分布，从而估计和p(x|y)和p(y)，基于这样的先验数学模型进行后续的计算。而先验估计过程中通常是从别的数据集获悉的先验分布中，基于某个潜在的参数z迁移过来的如下式，这样就能基于既有的后验分布，约束H假设空间。</p>
<div>
$$ 
x \sim \int p(x | z ; \theta) p(z ; y) d z
 $$
</div>
<p>通常在识别，生成，反转，重建中有较常见的应用</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200529163340216.png">
    <img alt="image-20200529163340216" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200529163340216.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200529163340216.png" style="display: block; margin: 0 auto;"
      alt="image-20200529163340216"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ul>
<li>
<p><strong>Decomposable Components：</strong>
<strong>基于人类</strong>的认知，将数据分解成组件级别，在进行后续的识别和重组；利用类间的通用性；</p>
</li>
<li>
<p><strong>Groupwise Shared Prior：</strong>
新的FS类别，先通过无监督学习分组，共享组内的类别先验，然后基于组内的先验对其进行建模。</p>
</li>
<li>
<p>**Parameters of Inference Networks：**网络参数推理</p>
</li>
</ul>
<div>
$$ 
  p(z | x ; \theta, \gamma)=\frac{p(x, z ; \theta, y)}{p(x ; y)}=\frac{p(x | z ; \theta) p(z ; \gamma)}{\int p(x | z ; \theta) p(z ; \gamma) d z}
  $$
</div>
<p>为了找到最优的 $\theta$ ，必须最大化以上的后验概率：</p>
<p>基于数据对其进行求解，inference network能够高效的迁移到新任务，但是inference network 需要大量的参数，所以通常需要在辅助的大规模数据集训练后才使用。很多经典的推理网络都可以在FSL上应用，比如VAE（可变自动编码器），autoregressive model，GAN，VAE+GAN</p>
<h4 id="summary2">Summary2</h4>
<p>详细的优缺点，参考文章</p>
<ol>
<li>存在相似任务或者辅助任务：多任务学习 ​</li>
<li>包含足够的各种类别的大规模数据集：embedding方法</li>
<li>存在可用的内存网络：在内存顶部训练一个简单的模型（分类器），可以简单的用于FSL，主要是要精心设计更新规则。</li>
<li>除了FSL还想要执行生成和重构的任务的时候：generative modeling</li>
</ol>
<h3 id="algorithm">ALGORITHM</h3>
<p>算法层面的改进指的是在最优空间H搜索H*的策略，最基础的有SGD。:x:在FSL的情况下，数据会使得更新次数不够多，同时也没法基于交叉验证找到合适的补偿之类的。:arrows_counterclockwise:本节中的方法用先验知识来影响 $\theta$ ，具体体现为：:one:良好的初值；:two:直接学习优化器以输出搜索步骤；​</p>
<p>:zap:基于先验知识对策略的影响，对算法进行分类</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200529224457034.png">
    <img alt="image-20200529224457034" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200529224457034.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200529224457034.png" style="display: block; margin: 0 auto;"
      alt="image-20200529224457034"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h4 id="refining-existing-parameters">Refining Existing Parameters</h4>
<p>:jack_o_lantern:基本思想：从相关任务中预训练模型的 $\theta$ 0作为一个良好的初始化，然后基于训练集的几次训练来adapt。</p>
<ul>
<li>
<p>Fine-Tuning Existing Parameter by Regularization：
如何解决overfit的问题是此类预训练算法设计关键：其中一种方式就是依赖正则化操作来adapt参数。

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200529230946081.png">
    <img alt="image-20200529230946081" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200529230946081.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200529230946081.png" style="display: block; margin: 0 auto;"
      alt="image-20200529230946081"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>

正则化的方式主要有以下几种：</p>
<table>
  <thead>
      <tr>
          <th>Method</th>
          <th>Analysis</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Early-stopping</td>
          <td>监视训练过程，性能没有提高则停止学习</td>
      </tr>
      <tr>
          <td>Selectively updating $\theta$</td>
          <td>根据具体问题，选择需要的部分来更新参数，不更新所有参数</td>
      </tr>
      <tr>
          <td>Updating related parts of $\theta$ together</td>
          <td>聚类 $\theta$ ，然后共同更新每个组，BP更新 $\theta$</td>
      </tr>
      <tr>
          <td>Using a model regression network</td>
          <td>捕获任务无关的transformation，基于function进行embedding的映射？</td>
      </tr>
      <tr>
          <td></td>
          <td></td>
      </tr>
  </tbody>
</table>
</li>
<li>
<p>Aggregating a Set of Parameters：
聚合相关模型：不贴切的比如眼口鼻到脸；具体使用上，unlabeled/similar label dataset,的pretrain model参数到FSL参数的适应。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200529235519894.png">
    <img alt="image-20200529235519894" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200529235519894.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200529235519894.png" style="display: block; margin: 0 auto;"
      alt="image-20200529235519894"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ul>
<li>
<p>unlabeled dataset:
把相似样本分组聚类，然后adapt</p>
</li>
<li>
<p>similar dataset:
替换相似类别中的特征，重新使用已训练的分类器，然后对新类调整分类阈值。</p>
</li>
</ul>
</li>
<li>
<p>Fine-Tuning Existing Parameter with New Parameters：
仅仅对模型迁徙可能没办法对FSL完全编码，所以我们在对参数进行adapt的时候加入一个新的参数，然后再Dtrain中同时adapt现存参数和learn新参数

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200530001254775.png">
    <img alt="image-20200530001254775" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200530001254775.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200530001254775.png" style="display: block; margin: 0 auto;"
      alt="image-20200530001254775"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
</li>
</ul>
<h4 id="refining-meta-learned-parameter">Refining Meta-Learned Parameter</h4>
<p>本节中细化meta-learned的参数学习： $\theta$ 再过程中是持续优化的，不是固定的。

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200530001506867.png">
    <img alt="image-20200530001506867" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200530001506867.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200530001506867.png" style="display: block; margin: 0 auto;"
      alt="image-20200530001506867"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>Model-Agnostic Meta-Learning（MAML）通过梯度下降来元学习 $ \theta$  ,基于该参数，得到任务特定参数 $\phi<del>s$ ,更新公式类似如下形式 $\phi_{s}=\theta_{0}-\alpha \nabla_{\theta_{0}} \mathcal{L}<em>{\mathrm{train}}^{s}\left(\theta</em>{0}\right) . $ 其中 $L^s train$ 是训练样本的损失和， $\alpha $ 是步长，该参数 $\phi</del>s$ ,对于样本的顺序不受影响，此外元学习中基本的参数更新公式如下 $\theta_{0} \leftarrow \theta_{0}-\beta \nabla_{\theta_{0}} \sum_{T_{s} \sim P(T)} \mathcal{L}<em>{\text {test }}^{s}\left(\theta</em>{0}\right)$ ，其中测试误差是整个过程中损失的和。通过元学习将参数转移。</p>
<p>最近针对MAML提出了主要再以下三个方面的改进：</p>
<ul>
<li>:zap:合并特定任务的信息：MAML为所有任务提供相同的初始化，但是这样忽视了特异性，所以，从一个好的初始化参数的子集中为新任务选择初值</li>
<li>:zap:使用meta-learned $\theta$ 的不确定性去建模：结合AL</li>
<li>:zap:改进refining过程：对 $T~s$ 使用正则化？</li>
</ul>
<h4 id="learning-the-optimizer">Learning the Optimizer</h4>
<p>不使用梯度下降，学习一种可以直接输出更新的优化器，无需调整步长 $\alpha$ 和搜索方向。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200530010815362.png">
    <img alt="image-20200530010815362" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200530010815362.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200530010815362.png" style="display: block; margin: 0 auto;"
      alt="image-20200530010815362"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>LSTM+Meta-Learner？</p>
<h4 id="discussion-and-summary">Discussion and Summary:</h4>
<p>通过对现有参数进行微调，从而减少H需要的搜索量：</p>
<ul>
<li>使用现有 $\theta$ 作为初始化：牺牲一些精度换取速度</li>
<li>另外两种策略都是依赖于元学习，元学习可以让参数和指定任务更为接近，还有一种直接充当优化器。</li>
</ul>
<h3 id="future-works">Future Works</h3>
<ul>
<li>在未来的FSL中使用多模态的prior knowledge</li>
<li>SOTA网络架构的使用来改进data，algorithm，model；</li>
<li>AutoML在FSL任务中的应用</li>
<li>meta-learning中动态学习中，如何避免catastrophic forgetting</li>
<li>在各领域中的应用：CV，bot，NLP，Acoustic signal process，etc</li>
</ul>
<p>:zap:<strong>Theories：</strong></p>
<ul>
<li>
<p>FSL使用先验知识来弥补缺少监管信息的情况；</p>
</li>
<li>
<p>FSL很多时候和domain adaptation 有关系</p>
</li>
<li>
<p>FSL的收敛性研究还没有完全了解</p>
</li>
</ul>
<h2 id="appendix">Appendix</h2>
<h3 id="reference">Reference:</h3>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200530163634335.png">
    <img alt="image-20200530163634335" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200530163634335.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20200530163634335.png" style="display: block; margin: 0 auto;"
      alt="image-20200530163634335"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>之后整理一些可能需要阅读的reference</p>
<ol>
<li>
<p>只关注小样本的概念学习和经验学习的Another FSL survey:
J. Shu, Z. Xu, and D Meng. 2018. Small sample learning in big data era. arXiv preprint arXiv:1808.04572 (2018).</p>
</li>
<li>
<p>FS-RL，在仅给出少量状态和动作对组成的轨迹的情况下找到一种策略：</p>
<p>[3,33]</p>
</li>
<li>
<p>Bayesian Learning :
[35,76]</p>
</li>
<li></li>
</ol>
<h3 id="additional-vocabulary">Additional Vocabulary：</h3>
<table>
  <thead>
      <tr>
          <th>序号</th>
          <th>希腊字母</th>
          <th>Markdoown</th>
          <th>序号</th>
          <th>希腊字母</th>
          <th>Markdoown</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>1</td>
          <td>α</td>
          <td>\alpha</td>
          <td>19</td>
          <td>β</td>
          <td>\beta</td>
      </tr>
      <tr>
          <td>2</td>
          <td>γ</td>
          <td>\gamma</td>
          <td>20</td>
          <td>δ</td>
          <td>\delta</td>
      </tr>
      <tr>
          <td>3</td>
          <td>Γ</td>
          <td>\Gamma</td>
          <td>21</td>
          <td>Δ</td>
          <td>\Delta</td>
      </tr>
      <tr>
          <td>4</td>
          <td>ε</td>
          <td>\varepsilon</td>
          <td>22</td>
          <td>ϵ</td>
          <td>\epsilon</td>
      </tr>
      <tr>
          <td>5</td>
          <td>ζ</td>
          <td>\zeta</td>
          <td>23</td>
          <td>η</td>
          <td>\eta</td>
      </tr>
      <tr>
          <td>6</td>
          <td>Θ</td>
          <td>\Theta</td>
          <td>24</td>
          <td>ι</td>
          <td>\iota</td>
      </tr>
      <tr>
          <td>7</td>
          <td>θ</td>
          <td>\theta</td>
          <td>25</td>
          <td>κ</td>
          <td>\kappa</td>
      </tr>
      <tr>
          <td>8</td>
          <td>Λ</td>
          <td>\Lambda</td>
          <td>26</td>
          <td>λ</td>
          <td>\lambda</td>
      </tr>
      <tr>
          <td>9</td>
          <td>μ</td>
          <td>\mu</td>
          <td>27</td>
          <td>ν</td>
          <td>\nu</td>
      </tr>
      <tr>
          <td>10</td>
          <td>ξ</td>
          <td>\xi</td>
          <td>28</td>
          <td>ο</td>
          <td>\omicron</td>
      </tr>
      <tr>
          <td>11</td>
          <td>Π</td>
          <td>\Pi</td>
          <td>29</td>
          <td>ρ</td>
          <td>\rho</td>
      </tr>
      <tr>
          <td>12</td>
          <td>π</td>
          <td>\pi</td>
          <td>30</td>
          <td>τ</td>
          <td>\tau</td>
      </tr>
      <tr>
          <td>13</td>
          <td>Σ</td>
          <td>\Sigma</td>
          <td>31</td>
          <td>Φ</td>
          <td>\Phi</td>
      </tr>
      <tr>
          <td>14</td>
          <td>σ</td>
          <td>\sigma</td>
          <td>32</td>
          <td>ϕ</td>
          <td>\phi</td>
      </tr>
      <tr>
          <td>15</td>
          <td>Υ</td>
          <td>\Upsilon</td>
          <td>33</td>
          <td>Ψ</td>
          <td>\Psi</td>
      </tr>
      <tr>
          <td>16</td>
          <td>υ</td>
          <td>\upsilon</td>
          <td>34</td>
          <td>ψ</td>
          <td>\psi</td>
      </tr>
      <tr>
          <td>17</td>
          <td>Ω</td>
          <td>\Omega</td>
          <td>35</td>
          <td>ω</td>
          <td>\omega</td>
      </tr>
      <tr>
          <td>18</td>
          <td>φ</td>
          <td>\varphi</td>
          <td>36</td>
          <td>Ξ</td>
          <td>\Xi</td>
      </tr>
  </tbody>
</table>
<p>术语或生词:</p>
<ul>
<li>empirical risk minimizer ：经验风险最小化器</li>
<li>ultimate goal ：最终目的</li>
<li>To name a few： 举几个例子</li>
<li>autonomous driving car：自动驾驶汽车</li>
<li>tackled：解决</li>
<li>paradigm：范式</li>
<li>ethic：道德</li>
<li>taxonomy：分类</li>
<li><strong>the pros and cons of</strong> different approaches：不同方法的利弊</li>
<li>with respect to：关于</li>
<li>the approximation error：逼近误差</li>
<li>the estimation error：估计误差</li>
<li>alleviate：缓和，减轻</li>
<li>aggregation：聚集</li>
<li>simultaneously：同时，兼</li>
<li>penalized：受惩罚的</li>
<li>hybrid:混合的</li>
<li>interleaved：交错的</li>
<li>denominator：分母</li>
</ul>
<p>注意区分：</p>
<ul>
<li>sufficient：足够</li>
<li>terminology：术语</li>
<li>refine：提炼 提纯</li>
<li>leverage：利用</li>
<li>latent：潜在的</li>
</ul>
<h2 id="faq">FAQ</h2>
<ul>
<li><input checked="" disabled="" type="checkbox"> Testing Set需要在N-way上进行吗？应该是要的</li>
<li><input checked="" disabled="" type="checkbox"> AL的query or oracle 是啥意思</li>
<li><input checked="" disabled="" type="checkbox"> According to whether the oracle or human intervention is leveraged, this can be further classified into the following
此处 oracle到底是什么意思</li>
<li><input checked="" disabled="" type="checkbox"> Semi-Supervised 又和FSL有什么区别呢</li>
<li><input checked="" disabled="" type="checkbox"> Imbalance Learning确实不是很理解</li>
<li><input checked="" disabled="" type="checkbox"> Generative Modeling的具体要素不是很懂</li>
<li><input checked="" disabled="" type="checkbox"> Core Issue中的三个h的关系还有点疑惑
app：在最优的情况下，能搜索到的最优解和实际最优解之间的差距
est：实际的假设空间中的最优解和基于少量样本的经验得到的假设空间中的最优解之间的距离。</li>
<li><input checked="" disabled="" type="checkbox"> Parameters of Inference Networks，不知道怎么理解，后续要补充</li>
</ul>
<p>&ndash;</p>
<h3 id="需要思考的点">需要思考的点</h3>
<ul>
<li><input checked="" disabled="" type="checkbox"> <strong>Few-shot-learning &amp; meta learning的问题设置</strong>，就是多类中都有<strong>足量样本</strong>，然后随机的从多类中选取few-way和few-shot的data模拟多种meta环境（fewshot和fewway），单次训练都是小样本的情况，进行学习，在这种环境下学习到，一个模式，然后从而减少数据量的要求。（这样就哪里减少了数据量啊，我就没懂了，）</li>
<li><input checked="" disabled="" type="checkbox"> 那么假如说没有多类动作（怎么构造多类动作）：不会，我们可以在网上爬取，或者自己拍摄，因为只需要少量有标注的数据即可，也就是positive数据可以比较容易获得。</li>
<li><input checked="" disabled="" type="checkbox"> 那么我们在构造增量的时候，也是考虑边际效益，然后当数据量达到一定规模的时候可以采用直接训练分类器的分类器，来对效果进行分类</li>
<li><input checked="" disabled="" type="checkbox"> Few-shot-learning中，训练集和测试集，标签已知和未知到底怎么弄，从代码中以及定义中分析的话怎么感觉是两个意思。我们需要的应该不能用到那个。</li>
<li><input checked="" disabled="" type="checkbox"> few-shot-learning应该指的是，新类只有很少的样本，但是旧类还是有大量标注样本的情况这个我们要好好分析。</li>
</ul>
<h3 id="但是这样的创新点在于更多的是算法的组合有没有办法提出一个网络结构将这样的思路融合起来">但是这样的创新点在于更多的是算法的组合，有没有办法提出一个网络结构将这样的思路融合起来。！！！</h3>
]]></content:encoded>
    </item>
    <item>
      <title>C&#43;&#43;的常见数据类型和操作</title>
      <link>https://aikenh.cn/posts/cpp%E8%A6%81%E7%82%B9%E8%BE%A8%E6%9E%90%E4%B8%8E%E8%A1%A5%E5%85%85/</link>
      <pubDate>Sun, 28 Nov 2021 06:24:23 +0000</pubDate>
      <guid>https://aikenh.cn/posts/cpp%E8%A6%81%E7%82%B9%E8%BE%A8%E6%9E%90%E4%B8%8E%E8%A1%A5%E5%85%85/</guid>
      <description>Data Structure and Type</description>
      <content:encoded><![CDATA[<p>主要介绍一些常用数据类型的一些method，区别还有一些特殊的定义；</p>
<p>priority_queue 默认是大顶堆，great的话是小顶堆，less的话是大顶堆，自定义的话不知道是不是一致的</p>
<p>set默认top是小顶，这个大小我就不知道了，自定义的话，好像和我想得是一致的</p>
<p><strong>所有的动态容器都是存放在heap上的，像是什么Vector，String，unordered_map之类的</strong></p>
<h2 id="指定精度的输出和计算">指定精度的输出和计算</h2>
<p>在腾讯的笔试中出现的需要指定精度和指定的计算精度的分析，在使用常数的时候一定要使用.0去修正一个方法。</p>
<h2 id="vector-动态数组">Vector 动态数组</h2>
<p>Vector中的一些常用的函数，方法，以及一些属性介绍和辨析</p>
<h3 id="emplace_back--push_back在末尾添加元素">emplace_back &amp; push_back（在末尾添加元素）</h3>
<p><code>empalce_back </code>直接在数组的末尾进行构造，而<code>push_back</code>借助于构造的临时变量再将其加入数组末尾，所以在一些操作中<code>empalce_back</code>对于空间时间的效率是会更高的，但是如果我们有重复构筑的数据的话，可能就需要使用<code>push_back</code>。</p>
<p>要注意实际上vector中并<strong>没有</strong>append的方法。</p>
<h3 id="初始化方法">初始化方法</h3>
<p>主要有几种常用的构造函数，在这里主要介绍的是关于多维度的初始化构造方式。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">v</span> <span class="o">=</span> <span class="p">{</span><span class="mi">7</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">16</span><span class="p">,</span> <span class="mi">8</span><span class="p">};</span> <span class="c1">// 最基本的定义
</span></span></span><span class="line"><span class="cl"><span class="c1">// 通过大括号来设定多级的vector的初始值
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;&gt;</span> <span class="n">value</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="sc">&#39;5&#39;</span><span class="p">,</span><span class="sc">&#39;3&#39;</span><span class="p">,</span><span class="sc">&#39;.&#39;</span><span class="p">,</span><span class="sc">&#39;.&#39;</span><span class="p">,</span><span class="sc">&#39;7&#39;</span><span class="p">,</span><span class="sc">&#39;.&#39;</span><span class="p">,</span><span class="sc">&#39;.&#39;</span><span class="p">,</span><span class="sc">&#39;.&#39;</span><span class="p">,</span><span class="sc">&#39;.&#39;</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="sc">&#39;6&#39;</span><span class="p">,</span><span class="sc">&#39;.&#39;</span><span class="p">,</span><span class="sc">&#39;.&#39;</span><span class="p">,</span><span class="sc">&#39;1&#39;</span><span class="p">,</span><span class="sc">&#39;9&#39;</span><span class="p">,</span><span class="sc">&#39;5&#39;</span><span class="p">,</span><span class="sc">&#39;.&#39;</span><span class="p">,</span><span class="sc">&#39;.&#39;</span><span class="p">,</span><span class="sc">&#39;.&#39;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span> 
</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>常用的长度和常量</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">vec</span><span class="p">(</span><span class="n">size1</span><span class="p">,</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">(</span><span class="n">size2</span><span class="p">,</span><span class="n">defaultvalue</span><span class="p">));</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="unordered_mapset哈希结构">Unordered_map&amp;set哈希结构</h2>
<h3 id="cpp中hash-table的实现数据类型">CPP中hash table的实现数据类型：</h3>
<p>实际上就是无序表，针对不同情况下的基本的定义方式，理念相同，针对不同的应用场景</p>
<ul>
<li>
<p><code> unordered_map&lt;typedef,typedef&gt; Hashtable</code> : 实际上是Key-Value的架构</p>
</li>
<li>
<p><code>unordered_set&lt;typedef&gt; Hashset</code> ：只包含key的类型</p>
</li>
</ul>
<p>插入的话，可以使用数组的形式，也可以用insert 或者emplace把。</p>
<h3 id="取值方式">取值方式</h3>
<p>除了通过Key取Value这种老生常谈的方式，我们这里探讨的是iterator的情况下如何取到当前的值：</p>
<ol>
<li><strong>set</strong>: <code>*it</code>即可；</li>
<li><strong>map：</strong><code>*it</code>取的应该是value，<strong>key</strong>的话通过 <code>it-&gt;first</code>来取值，<strong>value</strong>通过<code>it-&gt;second</code></li>
</ol>
<h3 id="按照迭代器来初始化">按照迭代器来初始化</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">unordered_set</span><span class="o">&lt;</span><span class="n">string</span><span class="o">&gt;</span> <span class="n">deaded</span><span class="p">(</span><span class="n">deadends</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="n">deadends</span><span class="p">.</span><span class="n">end</span><span class="p">());</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="是否存在键值">是否存在键值</h3>
<p>使用<code>.count</code>不要再用find和end了，那个估计时间成本特别高了。。。。怎么更慢了。</p>
<p>使用map[key] 可以访问键对应的值，但是如果Key不存在，cpp会自动创建这个key同时赋值为0；</p>
<h3 id="erase">erase</h3>
<p>可以直接根据键值进行erase()</p>
<h2 id="list-双向链表like">List 双向链表like</h2>
<p>通常用<a href="https://zh.cppreference.com/w/cpp/container/list" target="_blank" rel="noopener">list</a>
来实现类似双向链表的类型，基本的使用上好像和其他的容器没什么区别，没有index索引，可能需要用iteration来进行遍历操作，</p>
<ul>
<li>和双向队列相同，可以在两端添加和删除，pop push emplace也就是有_back和_front的后缀。</li>
<li>自带reverse，可以将元素的顺序反转；</li>
<li>unique可以删除连续的重复元素；</li>
<li>sort自带排序算法；</li>
</ul>
<h2 id="pair-二元元组对">Pair 二元元组对</h2>
<h3 id="二元tuple类型">二元tuple类型</h3>
<p>实际上应该就是python中的二元tuple，也就是包含两个元素的数据结构，都是公开，可以是同样类别或者不同类别的，再STL中。</p>
<h3 id="usage">USAGE：</h3>
<p>初始化：基本的初始化方式如下</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">pair</span><span class="o">&lt;</span><span class="n">type1</span><span class="p">,</span> <span class="n">type2</span><span class="o">&gt;</span> <span class="n">Data1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 基本的调用方式如下
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">Data1</span><span class="p">.</span><span class="n">first</span> <span class="o">=</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"><span class="n">Data2</span><span class="p">.</span><span class="n">second</span> <span class="o">=</span> <span class="p">{};</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>用作新的类型定义的方式</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">typedef</span> <span class="n">pair</span><span class="o">&lt;</span><span class="n">type1</span><span class="p">,</span> <span class="n">type2</span><span class="o">&gt;</span> <span class="n">newtypeName</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">newtypeName</span> <span class="n">Data2</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>实际上再DP中也是比较常见的，因为有一些情况下需要额外的信息存储就会使用这个类型。</p>
<h2 id="string--char-字符串">String &amp; char 字符串</h2>
<h3 id="一些常用的函数">一些常用的函数</h3>
<p>strcpy：将stringA 的值复制到stringB</p>
<p>strcat：直接用+就行了</p>
<h2 id="queue队列">queue队列</h2>
<p>实际上就是队列数据结构的CPP实现，基本的特征和队列的要求是一致的，常在BFS中使用到。</p>
<h3 id="常用的成员函数和操作">常用的成员函数和操作</h3>
<ol>
<li><code>front/back</code>：访问首/尾元素;</li>
<li><code>push/emplace/pop</code>: 在末尾插入/构造数据；弹出队首数据；</li>
<li><code>swap</code>：交换内容（还没尝试过使用的方式）;</li>
</ol>
<h3 id="deque双端队列">Deque双端队列</h3>
<p>有下标顺序的容器，允许在首尾两端快速插入和删除，相比于原本的普通队列，元素访问上没什么区；主要的区别在于</p>
<ol>
<li>pop、emplace、push都变成了两种形式：<code>pop_back\ pop_front</code> &hellip;etc.</li>
</ol>
<h3 id="priority_queue优先队列">Priority_queue优先队列</h3>
<p><a href="https://blog.csdn.net/weixin_36888577/article/details/79937886" target="_blank" rel="noopener">参考资料</a>
 “例如，用 std::greaterT 将导致最小元素作为 <a href="https://zh.cppreference.com/w/cpp/container/priority_queue/top" target="_blank" rel="noopener">top()</a>
 出现。”</p>
<h4 id="usage-基本使用方式">Usage 基本使用方式</h4>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">priority_queue</span><span class="o">&lt;</span><span class="n">type</span><span class="p">,</span> <span class="n">container</span><span class="p">,</span> <span class="n">compare</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="err">存放的数据类型，底层的容器类型，比较方程</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>基本的使用</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">top</span>
</span></span><span class="line"><span class="cl"><span class="n">push</span><span class="err">、</span><span class="n">pop</span><span class="err">、</span><span class="n">emplace</span>
</span></span><span class="line"><span class="cl"><span class="n">swap</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="priority_queue与multiset辨析">Priority_queue与Multiset辨析：</h3>
<p>实际上set和map这些数据结构是基于红黑树进行建立的，而优先队列是基于<strong>最大堆最小堆</strong>来建立的，虽然他们都有序，但是实际上他们的结构还是大不相同的。</p>
<p>堆本身是一个完全二叉树（除了最后一层以外都是满的，而且空的值都在右侧），同时满足夫节点大于所有子节点</p>
<p>Set本身是一个自平衡的BST（红黑树）：</p>
<blockquote>
<p>红黑树是一种近似平衡的二叉查找树，它能够确保任何一个节点的左右子树的高度差不会超过二者中较低那个的一倍</p>
</blockquote>
<h2 id="setmultiset-堆相关的数据类型">set/multiset 堆相关的数据类型</h2>
<p>比起说是堆，实际上就是集合的意思，但是这两个数据类型，本质上是基于红黑树等数据结构的基础设计（实现）的，很容易能转化为最大值堆和最小值堆。</p>
<h3 id="两者之间的基础区别">两者之间的基础区别：</h3>
<p>两者都包含在<code>&lt;set&gt;</code>中，进入这两个数据结构的数据都是会直接被排序好的（迭代器输出的话是从小到大的顺序排列），支持插入，删除，查找。</p>
<ol>
<li>set不允许重复元素的录入，会自动屏蔽重复元素；</li>
<li>multiset可以容忍元素的重复，也就是不会做统筹处理；</li>
</ol>
<h3 id="usage使用方式">Usage使用方式：</h3>
<p>可以通过在初始化的时候自定义compare，来规定排序的方向（来构建<strong>最大堆</strong>和<strong>最小堆</strong>），这里就涉及到了一下的两部分内容：</p>
<h4 id="lessgreater的使用和介绍">less、greater的使用和介绍</h4>
<p>两者包含在<code>functional</code>中</p>
<p>是系统定义好的基本bool比较器，前者就是当A小于B的时候会return true；后者应该是反过来的；</p>
<p>在一些函数或者类型定义的时候会使用到这两者的参数，避免我们的重复定义。</p>
<p>:question:但是这里目前有一个问题就是他这里介绍的使用方式来建立最大值和最下值堆，和我个人理解的不太一样，我们需要去后面辨析一下到底是怎么样才是对的。</p>
<p>应该和我理解的是一眼的，less最终就会是升序排列的，greater就会是降序排列的集合，然后只要我们在下面的pop或者push中指定一样的compare function就行。不，和我理解的是相反的</p>
<h4 id="push_heap--pop_heap堆元素的添加和删除">push_heap  pop_heap堆元素的添加和删除</h4>
<p>帮助通过最大值堆和最小值堆的数据的添加和删除；此外我们在这里可能需要额外的介绍一下<code>make_heap</code>，应该也是heap的系列套件，不知道是从什么数据类型开始来帮助建立堆，我们后续需要补充一下。</p>
<ol>
<li>通过<code>push_heap</code>能够实现堆元素的添加同时并不破坏数据结构，实际上应该也就是实现了shiftup之类的操作。</li>
<li>而通过<code>pop_heap</code>的话，实际上实现的是将要弹出的元素换到了末尾，这样我们从0，n-2的元素就是重构好的最大/小堆。必要的时候我们需要手动调用<code>pop_back()</code>，来对要弹出的元素进行实质上的弹出。</li>
<li><code>make_heap</code>将一个可迭代容器按照指定的compere建立成堆，默认是最大堆，输入的是begin，end，compa，</li>
</ol>
<h2 id="avl平衡二叉搜索树">AVL平衡二叉搜索树</h2>
<p>实际上就是在插入元素的时候实现两个操作：</p>
<ol>
<li>单旋转：插入的大小关系符合但是失衡的情况</li>
<li>双旋转：插入的大小关系不符合同时发生了失衡的情况</li>
</ol>
<p><a href="https://www.cnblogs.com/vamei/archive/2013/03/21/2964092.html" target="_blank" rel="noopener">平衡二叉树</a>
</p>
<h2 id="bb树红黑树">B+、B树、红黑树</h2>
<p>根节点最少有两个子女，每个中间节点都包含k-1个元素和k个孩子，每个叶子节点都包含k-1个元素，所有的叶子节点都位于同一层。</p>
<p>重点就在于节省io时间还有中间的节点数量等等</p>
<p>B树与B+树：https://blog.csdn.net/windflybird/article/details/79875972</p>
<p>红黑树：https://zhuanlan.zhihu.com/p/31805309</p>
<p>红黑树和AVL的区分：https://www.jianshu.com/p/37436ed14cc6 ；https://www.it610.com/article/1297797681401372672.htm</p>
<h2 id="swap-function">SWAP FUNCTION</h2>
<p>swap在实际操作的时候经常被用到，很多时候会被拿来代替删除等等的命令。</p>
<p>他适用的数据结构和数据类型以及传入的方式可以简单总结如下：</p>
<ol>
<li>初始定义就是交换两个变量之间的赋值，但是在各个数据类型中都存在swap的特化方程，所以<strong>根据该特化执行</strong>的情况下，等价于<code>varA.swap(varB)</code>，会交换其中的所有值；</li>
<li>通过基本的定义也能实现vector中两个不同index下的值的交换；</li>
</ol>
<h2 id="switch操作要常用">Switch操作要常用</h2>
<p>代替if else</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Solution</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">calculate</span><span class="p">(</span><span class="n">string</span> <span class="n">s</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">stk</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="kt">char</span> <span class="n">preSign</span> <span class="o">=</span> <span class="sc">&#39;+&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="kt">int</span> <span class="n">num</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">length</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">isdigit</span><span class="p">(</span><span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">]))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">num</span> <span class="o">=</span> <span class="n">num</span> <span class="o">*</span> <span class="mi">10</span> <span class="o">+</span> <span class="kt">int</span><span class="p">(</span><span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">-</span> <span class="sc">&#39;0&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">isdigit</span><span class="p">(</span><span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="o">&amp;&amp;</span> <span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">!=</span> <span class="sc">&#39; &#39;</span> <span class="o">||</span> <span class="n">i</span> <span class="o">==</span> <span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">switch</span> <span class="p">(</span><span class="n">preSign</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">case</span> <span class="sc">&#39;+&#39;</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">                    <span class="n">stk</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">num</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">                    <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="k">case</span> <span class="sc">&#39;-&#39;</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">                    <span class="n">stk</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="o">-</span><span class="n">num</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">                    <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="k">case</span> <span class="sc">&#39;*&#39;</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">                    <span class="n">stk</span><span class="p">.</span><span class="n">back</span><span class="p">()</span> <span class="o">*=</span> <span class="n">num</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                    <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="k">default</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">                    <span class="n">stk</span><span class="p">.</span><span class="n">back</span><span class="p">()</span> <span class="o">/=</span> <span class="n">num</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">                <span class="n">preSign</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">                <span class="n">num</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nf">accumulate</span><span class="p">(</span><span class="n">stk</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">stk</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="位操作运算">位操作运算</h2>
<p><a href="https://blog.csdn.net/cyuyan112233/article/details/40758031" target="_blank" rel="noopener">参考资料</a>
 <code>^</code>异或；<code>~</code>取反；<code>|</code>或；<code>&amp;</code> 与。</p>
<p>位运算符的优先级从高到低，依次为~、&amp;、^、|。</p>
<h3 id="基本的一些操作tips">基本的一些操作Tips</h3>
<p>根据剑指offer后面的两道题，我们可以分析一下怎么做到按位来进行操作</p>
<h2 id="exception-异常处理">Exception 异常处理</h2>
<p>介绍cpp中的断言等异常处理的语句：<code>assert</code> <code>try catch</code></p>
<h3 id="assert-断言">Assert 断言</h3>
<p>设置条件断点，当Expression == false 的时候终止程序运行， Just take one arguments （Expression）；</p>
<p>可以使用 <code>#define NOEDEBUG</code> 预处理符来终止程序中assert的作用。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// #define NODEBUG 
</span></span></span><span class="line"><span class="cl"><span class="c1">// 注释掉的时候assert是有效的
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">assert</span><span class="p">(</span><span class="mi">2</span><span class="o">+</span><span class="mi">2</span><span class="o">==</span><span class="mi">5</span><span class="p">);</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="try_catch--throw-异常捕捉和抛出">Try_Catch &amp; Throw 异常捕捉和抛出</h3>
<p>Throw就是Try中遇到异常执行的抛出语句，有默认的抛出类类型，我们也可以自定义抛出的值就是了，基本语法框架如下</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">try</span> <span class="p">{</span> <span class="cm">/* */</span> <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">exception</span><span class="o">&amp;</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span> <span class="cm">/* */</span> <span class="p">}</span> <span class="c1">// 具名形参
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">try</span> <span class="p">{</span> <span class="cm">/* */</span> <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">exception</span><span class="o">&amp;</span><span class="p">)</span> <span class="p">{</span> <span class="cm">/* */</span> <span class="p">}</span>  <span class="c1">// 不具名形参
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">try</span> <span class="p">{</span> <span class="cm">/* */</span> <span class="p">}</span> <span class="k">catch</span> <span class="p">(...)</span> <span class="p">{</span> <span class="cm">/* */</span> <span class="p">}</span>  <span class="c1">// 可被任何异常激活的catch
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>还有一个比较具体的例子可以表示如下</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">f</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">overflow_error</span><span class="o">&amp;</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 若 f() 抛出 std::overflow_error 则执行之（“相同类型”规则）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">runtime_error</span><span class="o">&amp;</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 若 f() 抛出 std::underflow_error 则执行之（“基类”规则）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">exception</span><span class="o">&amp;</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 若 f() 抛出 std::logic_error 则执行之（“基类”规则）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span> <span class="k">catch</span> <span class="p">(...)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 若 f() 抛出 std::string 或 int 或任何其他无关类型则执行之
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>然后介绍一下我们自己调用<code>throw</code>的方式：我们可以抛出任意类型的值，然后通过catch捕获该类型即可，示范如下：</p>
<p>不知道可不可以直接抛出“&hellip;”这种，下次试试。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Throwing an integer exception...</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">throw</span> <span class="mi">42</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; the integer exception was caught, with value: &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">i</span> <span class="o">&lt;&lt;</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="printf-按照format输出">Printf 按照format输出</h2>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span></span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code>#inlcude&lt;cstdio&gt;</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>参考cpp reference进行基本的学习吧，实际上</p>
<h2 id="accumulateisdigit">Accumulate，isdigit</h2>
<p>通过迭代器叠加其中的所有数字</p>
<p>isdigit：返回的是是否是0~9的字符把</p>
<h2 id="define定义函数">Define定义函数</h2>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#define nRand(n){rand() % n}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="指针相关内容">指针相关内容</h2>
<h3 id="函数指针">函数指针</h3>
<p>用typedef减少输入量的写法，实际应用在之前的cpp笔记中已经有了</p>
<h3 id="智能指针">智能指针</h3>
<p>unique_prt&lt;&gt;:会自己销毁的指针，管理的是堆对象，但是指针本身是随着栈，来进行管理的</p>
<p>shared_ptr&lt;&gt;：对于同一个对象会维护一个指向该对象的count，通过这个count，在count清零的时候自动析构该类</p>
<p>weak_ptr&lt;&gt;: 防止shared_ptr产生两个shard交互引用的情况，这样就永远不会被释放，通过weak指针，他不进行计数，当weak指针被销毁的时候就直接将空间释放，也不会使得技术++</p>
]]></content:encoded>
    </item>
    <item>
      <title>Linux 基础操作 01</title>
      <link>https://aikenh.cn/posts/linux/</link>
      <pubDate>Sun, 28 Nov 2021 06:24:21 +0000</pubDate>
      <guid>https://aikenh.cn/posts/linux/</guid>
      <description>config your linux from begin</description>
      <content:encoded><![CDATA[<h2 id="学习资源汇总">学习资源汇总</h2>
<p>manual：<a href="https://www.runoob.com/w3cnote/linux-common-command-2.html" target="_blank" rel="noopener">菜鸟Shell</a>
 | <a href="https://www.explainshell.com/explain/1/ps" target="_blank" rel="noopener">ExplainShell</a>
</p>
<p>收录一些Linux的工具书以及相关的OnLine-Doc，方便后续进行学习和查阅：</p>
<ol>
<li><a href="http://cn.linux.vbird.org/linux_basic/linux_basic.php" target="_blank" rel="noopener">鸟哥的Linux私房菜</a>
：相对全面一点但是内容有点太多了</li>
<li><a href="https://www.linuxprobe.com/chapter-00.html" target="_blank" rel="noopener">Linux就该这么学</a>
：从开始到结束的流程挺完善的，但是这个网站做的是纯傻逼</li>
<li><a href="https://linuxtools-rst.readthedocs.io/zh_CN/latest/index.html#" target="_blank" rel="noopener">Linux Tools Quick Tutorial</a>
：简单入门教程好像是</li>
<li>Linux命令行于Shell脚本编程大全：本地PDF，在当前文件夹下面进行查看</li>
</ol>
<h2 id="文件架构系统信息">文件架构&amp;系统信息</h2>
<p><a href="https://www.cnblogs.com/sijizhen/p/10576049.html" target="_blank" rel="noopener">Linux各文件夹的含义</a>
分析LInux下的文件架构体系，包括最外层的一些系统文件夹的基础作用以及对应的特殊功能等等，帮助我们能够更清楚我们文件的存储体系以及系统文件的存储地址。</p>
<ul>
<li><code>/tmp</code>：临时文件夹，系统会定期清理其中的文件，用来存放一些下载和安装的文件</li>
<li><code>/mnt</code>: mount挂载文件夹，作为挂载目录来使用，比如在WSL中，对应的就是windows系统的文件</li>
<li><code>/etc </code>:用来存放所有的系统管理所需要的配置文件和子目录，linux正是因为这些文件才能正常运行</li>
<li><code>/home</code>: 个人文件夹，在home下会有自己的user dir,通常情况下我们的工作区和对应的其余资料都会放在这个部分</li>
<li><code>/bin</code>: 是binary的缩写,包含了引导系统启动所需的命令和普通用户可以使用的常用命令</li>
<li><code>/root</code>: 系统管理员的主目录</li>
<li><code>/var</code>:这个目录中存放着那些不断在扩充着的东西，为了保持/usr的相对稳定那些经常被修改的目录可以放在这个目录下，实际上许多系统管理员都是这样干的顺带说一下系统的日志文件就在/var/log目录中。</li>
<li><code>/usr</code>: 最庞大的目录，要用到的应用程序和文件几乎都在这个目录</li>
</ul>
<h3 id="gpu--cpu信息">GPU &amp; CPU信息</h3>
<p>Linux查看显卡信息：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">lspci <span class="p">|</span> grep -i vga
</span></span><span class="line"><span class="cl"><span class="c1"># 如果是nvidia还可以</span>
</span></span><span class="line"><span class="cl">lspci <span class="p">|</span> grep -i nvidia
</span></span><span class="line"><span class="cl"><span class="c1"># 最常用：或者使用nvidia的自带命令</span>
</span></span><span class="line"><span class="cl">nvidia-smi</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>监视GPU使用情况</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">watch nvidia-smi
</span></span><span class="line"><span class="cl"><span class="c1"># or</span>
</span></span><span class="line"><span class="cl">gpustat --watch</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>显示CUDA版本</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cat /usr/local/cuda/version.txt</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>查看CPU：<a href="https://blog.csdn.net/qq_38025219/article/details/88849637" target="_blank" rel="noopener">相关信息</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">cat /proc/cpuinfo</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>显示CPU个数：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">cat /proc/cpuinfo <span class="p">|</span>grep <span class="s2">&#34;processor&#34;</span><span class="p">|</span>wc -l</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="软件安装工具介绍">软件安装工具介绍</h3>
<p>开源的 Linux 有许多发行版本，其中有不同类型的包管理器，<code>dnf</code> 和 <code>apt</code> 管理器分别针对 <code>rpm</code> 和 <code>deb</code> 的包，这里介绍一下 RPM 包管理器的发展。</p>
<p><code>RPM </code> (red-hat program manager) 其是最早的软件安装工具，最早只能基于源码安装，但是其无法分析安装的软件和已安装软件间的依赖关系，这样很容易导致在安装的时候出现问题; 于是后续有了 <code>Yum</code> ;</p>
<p><code>YUM</code> 管理了很多 rpm 软件包，并能自动分析其中的依赖关系，避免安装软件出错，但是 yum 仍然存在分析不准确和内存占用的问题，所以后面再2015年的时候又有了更新，也就是 <code>DNF</code>;</p>
<p><code>DNF</code> 和 yum 的使用命令是完全一致的，即从 <code>yum install &lt;package&gt;</code> 变成了 <code>dnf install &lt;package&gt;</code>;</p>
<h2 id="系统服务">系统服务</h2>
<p>Linux 中控制系统服务的命令在 RHEL5/6 中为 <code>service</code> ，而在 RHEL7/8 中则改为 <code>systemctl</code> ，其对应的使用范式分别为：</p>
<ul>
<li><code>service &lt;server&gt; &lt;action&gt;</code></li>
<li><code>systemctl &lt;action&gt; &lt;server&gt;</code></li>
</ul>
<p>其对应执行服务的 <code>&lt;action&gt;</code> 都是一致的，例如 start、restart 等服务启动命令。</p>
<h3 id="启动ssh服务">启动ssh服务</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">service ssh start
</span></span><span class="line"><span class="cl"><span class="c1"># or </span>
</span></span><span class="line"><span class="cl">systemctl restart sshd</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>ssh 配置免密登陆和远程登录，可以参考 <a href="https://aikenh.cn/cn/SSH/" target="_blank" rel="noopener">SSH 常用场景和操作</a>
 文章。</p>
<h3 id="添加用户以及赋予-sudo-权限">添加用户以及赋予 Sudo 权限</h3>
<p>存在两个命令 <code>useradd</code> 和 <code>adduser</code> 都能添加新用户，但是 <code>useradd</code> 不会设置用户目录和 unix-name 的选项，所以推荐使用 <code>adduser</code> 指令来新建用户。</p>
<blockquote>
<p>对应的删除命令为 <code>userdel</code> 和 <code>deluser</code>, 管理用户组的文件为 <code>/etc/group</code></p>
</blockquote>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">adduser &lt;aikenhong&gt;
</span></span><span class="line"><span class="cl"><span class="c1"># 安装之时输入密码后会提示你输入ROOM等个人信息可以跳过</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>为用户添加 root 权限</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span></span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code>sudo vim /etc/sudoers
# 可能需要w!来保存</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="基础环境配置">基础环境配置</h2>
<p>配置环境之前首先要清楚自己所使用的Linux发行版以及对应的内核版本，如果使用的是Ubuntu，可通过以下指令查看所属的版本：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">cat /proc/version
</span></span><span class="line"><span class="cl"><span class="c1"># or </span>
</span></span><span class="line"><span class="cl">cat /etc/issue</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在进行一切配置之前，首先使用<code>passwd</code>指令修改密码。</p>
<h3 id="编辑器-vim-or-neovim">编辑器 Vim or Neovim</h3>
<p>接下来是安装vim或者neovim（或是spacevim等各种变体），其中服务器上推荐以vim作为主力配置的编辑器，neovim和插件的版本迭代和兼容性差，应对版本更新需要更多的精力，相对没有那么稳定（暂时。</p>
<p>安装vim后手动创建配置文件</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo apt-get install vim </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>安装neovim，需要首先安装neovim的ppa发布源后，才能下载</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo apt-add-repository ppa:neovim-ppa/stable
</span></span><span class="line"><span class="cl">sudo apt-get update 
</span></span><span class="line"><span class="cl">sudo install neovim</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>安装vim的各种其他变体可参考对应的官方站点或github，在完成安装之后，就是配置其使用，这里vim和neovim的配置单独开blog来讲，个人的配置可参考：<a href="https://github.com/AikenH/configs_scripts" target="_blank" rel="noopener">AikensDotfile</a>
</p>
<h3 id="zsh--omz-install">ZSH &amp;&amp; OMZ Install：</h3>
<p>参考资料：<a href="https://0xffff.one/d/716" target="_blank" rel="noopener">WSL终端美化</a>
、<a href="https://zhuanlan.zhihu.com/p/58073103" target="_blank" rel="noopener">zsh &amp; oh-my-zsh 的配置与使用</a>
、
<a href="https://traceme.space/blog/page/6/zshoh-my-zshtmuxvimdocker/" target="_blank" rel="noopener">zsh、oh-my-zsh、tmux、vim</a>
</p>
<p><strong>查看</strong>当前使用的 shell：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="nv">$SHELL</span> 
</span></span><span class="line"><span class="cl"><span class="c1"># 可以产看系统默认的shell</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>安装Zsh和OMZ</strong>对命令行进行优化：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># 安装zsh，很多会内置，其一些语法和调用逻辑相比默认的bash更好</span>
</span></span><span class="line"><span class="cl">sudo apt-get install zsh
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># omz参考官网安装连接，可以使用wget、curl、or github</span>
</span></span><span class="line"><span class="cl">sh -c <span class="s2">&#34;</span><span class="k">$(</span>curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh<span class="k">)</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">sh -c <span class="s2">&#34;</span><span class="k">$(</span>wget https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh -O -<span class="k">)</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">git clone https://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh
</span></span><span class="line"><span class="cl">cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc
</span></span><span class="line"><span class="cl"> </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>切换默认终端</strong>，以及恢复：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">chsh -s /bin/zsh
</span></span><span class="line"><span class="cl">chsh -s /bin/bash root</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><a href="https://github.com/ohmyzsh/ohmyzsh/wiki/Themes" target="_blank" rel="noopener">官方主题</a>
预览，在zsh配置文件中修改<code>vim ~/.zshrc</code></p>
<p><strong>Zsh插件安装</strong>：<a href="https://segmentfault.com/a/1190000039860436" target="_blank" rel="noopener">zsh插件安装</a>
；<a href="https://www.jianshu.com/p/8a912dc8de57" target="_blank" rel="noopener">zsh插件配置 </a>
，主要是两个插件zsh-synyax-highlighting高亮命令和zsh-autosuggestions自动补全。</p>
<ol>
<li>语法高亮安装：</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git clone https://github.com/zsh-users/zsh-syntax-highlighting.git <span class="si">${</span><span class="nv">ZSH_CUSTOM</span><span class="k">:-</span><span class="p">~/.oh-my-zsh/custom</span><span class="si">}</span>/plugins/zsh-syntax-highlighting</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="2">
<li>自动补全安装：</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git clone https://github.com/zsh-users/zsh-autosuggestions <span class="si">${</span><span class="nv">ZSH_CUSTOM</span><span class="k">:-</span><span class="p">~/.oh-my-zsh/custom</span><span class="si">}</span>/plugins/zsh-autosuggestions</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这两个命令将插件安装到相应的位置中，找到后在.zshrc 中进行配置，再通过 <code>source ~/.zshrc</code> 刷新配置即可。</p>
<p>其他的一些插件推荐（除了上述两个需要额外下载的，其他大多都是内置的插件，zshrc 中设置后 source 即可）：<a href="https://www.5lian.ink/developer/%E6%8E%A8%E8%8D%90%E5%87%A0%E4%B8%AA%E5%B8%B8%E7%94%A8%E7%9A%84%20zsh%20%E6%8F%92%E4%BB%B6/" target="_blank" rel="noopener">推荐几个常用的 zsh 插件</a>
 |  <a href="https://blog.csdn.net/weixin_39802884/article/details/121721263" target="_blank" rel="noopener">ohmyzsh插件推荐_JASON凯伊</a>
 | <a href="https://github.com/ohmyzsh/ohmyzsh/wiki/Plugins" target="_blank" rel="noopener">Plugins·ohmyzsh/ohmyzsh Wiki</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>zshrc</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-zshrc" data-lang="zshrc"><span class="line"><span class="cl"><span class="nv">plugins</span><span class="o">=(</span>
</span></span><span class="line"><span class="cl">        z
</span></span><span class="line"><span class="cl">        git
</span></span><span class="line"><span class="cl">        zsh-syntax-highlighting
</span></span><span class="line"><span class="cl">        zsh-autosuggestions
</span></span><span class="line"><span class="cl">        colored-man-pages
</span></span><span class="line"><span class="cl">        safe-paste
</span></span><span class="line"><span class="cl">        themes
</span></span><span class="line"><span class="cl">        sudo
</span></span><span class="line"><span class="cl">        <span class="o">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>删除zsh后远程无法连接</strong>：可能是由于接受ssh启动的默认shell被改成了zsh，而zsh已经卸载，导致无法进入终端页面，因此需要想办法进入console，然后修改默认的登陆项为bash。<code>vim /etc/passwd</code>。</p>
<blockquote>
<p>zsh作为基本的shell，可以不删；此外若要删除，记得优先将默认启动项改回bash，此外，不要修改root的默认登录shell，<a href="https://www.v2ex.com/amp/t/270407?__cf_chl_jschl_tk__=6264f73af1e0c5f14959dfe3604b3da795b3d4da-1602866582-0-AUHrxUdAsZyuwjIUeBGnWQk2x9m6JknAuUFnv_qwxCjCjaoGV7HaIyGQK7SX0QYCHTb6ccqqxizj0GWSRT0gwCDPIh_0G41kPJ14qBcs8570f6hF1r86Lx3o1VkOSC3JXbNzrH6ybDKpmyPmZtPFnfRtPFabzNlgFjbqE8cV_BDenHLDsSBAkENttf13tiKG39tLcUdWcZXQfwVOmyLkoNajKXCqFXwAFSwXqHyW1egKxBQ1bkmCllJGtyBh9D0CD0VsRq6vjVpfeenxOc-1XEqCEPQ2ahzDWEMfNzfjnYcktOSWpkhnUFbqw0L1vss8Y9jG7uooSAxoGS1tgr_XfT022kedjZm1fVCd4AmwSGvo" target="_blank" rel="noopener">LINK</a>
</p>
</blockquote>
<p><strong>Conda 相关指令消失：</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># 基于别的shell，例如bash，执行</span>
</span></span><span class="line"><span class="cl">conda init zsh</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>添加Alias</strong>方便使用，个人常用的一些alias如下:</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">g</span><span class="o">=</span><span class="s2">&#34;git&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">ltr</span><span class="o">=</span><span class="s2">&#34;ls -rsthl&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">lwc</span><span class="o">=</span><span class="s2">&#34;ll | grep &#39;^-&#39; | wc -l &#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">cl</span><span class="o">=</span><span class="s2">&#34;clear&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">nvim</span><span class="o">=</span><span class="s2">&#34;vim -u {my .vimrc}&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">hsp</span><span class="o">=</span><span class="s2">&#34;history | grep &#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="进程管理-monitors">进程管理 Monitors</h3>
<p>进程和性能检测工具安装，可以检测系统的运行状态，以及对相应的进程进行查看，同时也能起到装逼的作用，主要有以下几个工具：<code>Htop</code>，<code>Bottom</code>，<code>Zenith</code></p>
<p>Htop 是最general且相对实用的一个版本，主要侧重于进程管理，安装也最为简单。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo apt-get install htop
</span></span><span class="line"><span class="cl">htop</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>Bottom 需要下载对应内核的安装包后再命令行中执行安装指令，因此也需要curl来下载对应的软件包：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># 以ubuntu为例，下载deb版本</span>
</span></span><span class="line"><span class="cl">curl -s https://api.github.com/repos/ClementTsang/bottom/releases/latest <span class="p">|</span> grep browser_download_url <span class="p">|</span> grep amd64.deb <span class="p">|</span> cut -d <span class="s1">&#39;&#34;&#39;</span> -f <span class="m">4</span> <span class="p">|</span> wget -qi -
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">sudo apt install ./bottom*.deb
</span></span><span class="line"><span class="cl">btm</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>Zenith 可能需要系统中支持cargo或者rust，安装放方式类似btm，但是两者之间可做一个相互替代，均着重于可视化系统用量，因此二选一即可：</p>
<p>首先安装rust</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo apt-get install rustc</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>下载对应的安装包，解压，并安装</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># download the package of Zenith</span>
</span></span><span class="line"><span class="cl">curl -s https://api.github.com/repos/bvaisvil/zenith/releases/latest <span class="p">|</span> grep browser_download_url <span class="p">|</span> grep linux <span class="p">|</span> cut -d <span class="s1">&#39;&#34;&#39;</span> -f <span class="m">4</span> <span class="p">|</span> wget -qi -
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># unzip it and install</span>
</span></span><span class="line"><span class="cl">tar -xvf zenith.linux.tgz
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># change the mode of shell</span>
</span></span><span class="line"><span class="cl">chmod +x zenith
</span></span><span class="line"><span class="cl">sudo mv zenith /usr/local/bin</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>似乎从源码编译能支持GPU的信息显示，后续有需要的情况下进行拓展。</p>
<p>参考资料:</p>
<ul>
<li><a href="https://computingforgeeks.com/top-terminal-based-monitoring-tools-for-linux/" target="_blank" rel="noopener">Top Terminal Based Monitoring Tools for Linux | ComputingForGeeks</a>
</li>
<li><a href="https://reposhub.com/linux/miscellaneous/bvaisvil-zenith.html" target="_blank" rel="noopener">Zenith (reposhub.com)</a>
</li>
<li><a href="https://github.com/ClementTsang/bottom" target="_blank" rel="noopener">ClementTsang/bottom (github.com)</a>
</li>
<li><a href="https://github.com/bvaisvil/zenith" target="_blank" rel="noopener">bvaisvil/zenith (github.com)</a>
</li>
</ul>
<h3 id="zip支持">ZIP支持</h3>
<p>tgz应该是linux内置的压缩命令，而许多时候在windows中的压缩包会有zip等格式，所以这里也添加一下ZIP支持。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo apt-get install zip </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>zip指令的基础使用如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># r means recurrent</span>
</span></span><span class="line"><span class="cl">zip -r newpackage.zip dir1</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># -d 解压到特定文件夹</span>
</span></span><span class="line"><span class="cl">unzip package.zip -d dir/*</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">-m: 压缩文件删除源文件
</span></span><span class="line"><span class="cl">-o: 将压缩文件的最新变动时间设置为压缩的时间
</span></span><span class="line"><span class="cl">-r: 递归压缩，目录下的所有子级目录一并压缩
</span></span><span class="line"><span class="cl">-x: “文件列表”，压缩时排除文件列表中的文件</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="额外配置">额外配置</h2>
<p>只保留必要的额外配置，帮助系统的使用更加便捷，遵循奥卡姆剃刀原则。</p>
<h3 id="资源管理器-ranger">资源管理器 Ranger</h3>
<p><strong>安装Ranger</strong></p>
<p>参考<a href="https://github.com/ranger/ranger" target="_blank" rel="noopener">offical-site</a>
，可使用对应发行版本的package-manager进行安装：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo apt-get install ranger</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>配置Ranger</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">ranger --copy-config<span class="o">=</span>all</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>该命令能将基础的配置复制到相应的地址，随后根据我们的需要对其进行配置，包括是否启用边框等，配置结构如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>text</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">rc.conf     - 选项设置和快捷键
</span></span><span class="line"><span class="cl">commands.py - 能通过 : 执行的命令
</span></span><span class="line"><span class="cl">rifle.conf  - 指定不同类型的文件的默认打开程序。
</span></span><span class="line"><span class="cl">scope.sh    - 用于指定预览程序的文件</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这些生成的配置文件的所在目录为：<code>/Users/test/.config/ranger/</code></p>
<p>详细配置参考资料：<a href="https://www.52gvim.com/post/ranger-tool-usage" target="_blank" rel="noopener">Ranger使用</a>
</p>
<h3 id="终端复用器-tmux">终端复用器 Tmux</h3>
<p>为了避免远程终端执行的代码由于ssh连接的不稳定而中断，可以使用nohup挂起进程，或者使用tmux和screen类的session软件来保持进程，但是鉴于Tmux优秀的终端复用和诸多特性，这里选择tmux。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo apt-get install tmux</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>配置TMUX</strong></p>
<p>新版本的时候出现了问题，等待更新，<a href="https://github.com/tmux/tmux/blob/master/example_tmux.conf" target="_blank" rel="noopener">official example</a>
，<a href="http://louiszhai.github.io/2017/09/30/tmux/#%E6%96%B0%E5%A2%9E%E9%9D%A2%E6%9D%BF" target="_blank" rel="noopener">tutor</a>
</p>
<p>在<code>~</code>目录下生成配置文件，然后写入我们希望的配置，后续合并到Dotfile中</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">vim ~/.tmux.conf</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>主要包含相关的按键映射以及页面主题等等操作</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># use alt+arrpw to switch panes</span>
</span></span><span class="line"><span class="cl"><span class="nb">bind</span> -n M-Left <span class="k">select</span>-pane -L
</span></span><span class="line"><span class="cl"><span class="nb">bind</span> -n M-Right <span class="k">select</span>-pane -R
</span></span><span class="line"><span class="cl"><span class="nb">bind</span> -n M-Up <span class="k">select</span>-pane -U
</span></span><span class="line"><span class="cl"><span class="nb">bind</span> -n M-Down <span class="k">select</span>-pane -D
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># mouse mode</span>
</span></span><span class="line"><span class="cl"><span class="nb">set</span> -g mouse on
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># set easier window split keys</span>
</span></span><span class="line"><span class="cl">bind-key v split-window -h
</span></span><span class="line"><span class="cl">bind-key h split-window -v
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#Enable oh my zsh in tmux</span>
</span></span><span class="line"><span class="cl"><span class="nb">set</span> -g default-command /usr/bin/zsh
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#################################### config color ######################################</span>
</span></span><span class="line"><span class="cl"><span class="nb">set</span> -g default-terminal <span class="s2">&#34;screen-256color&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">## COLORSCHEME: gruvbox dark</span>
</span></span><span class="line"><span class="cl">set-option -g status <span class="s2">&#34;on&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># default statusbar color</span>
</span></span><span class="line"><span class="cl">set-option -g status-style <span class="nv">bg</span><span class="o">=</span>colour237,fg<span class="o">=</span>colour223 <span class="c1"># bg=bg1, fg=fg1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># default window title colors</span>
</span></span><span class="line"><span class="cl">set-window-option -g window-status-style <span class="nv">bg</span><span class="o">=</span>colour214,fg<span class="o">=</span>colour237 <span class="c1"># bg=yellow, fg=bg1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># default window with an activity alert</span>
</span></span><span class="line"><span class="cl">set-window-option -g window-status-activity-style <span class="nv">bg</span><span class="o">=</span>colour237,fg<span class="o">=</span>colour248 <span class="c1"># bg=bg1, fg=fg3</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># active window title colors</span>
</span></span><span class="line"><span class="cl">set-window-option -g window-status-current-style <span class="nv">bg</span><span class="o">=</span>red,fg<span class="o">=</span>colour237 <span class="c1"># fg=bg1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># pane border</span>
</span></span><span class="line"><span class="cl">set-option -g pane-active-border-style <span class="nv">fg</span><span class="o">=</span>colour214 <span class="c1">#fg2</span>
</span></span><span class="line"><span class="cl">set-option -g pane-border-style <span class="nv">fg</span><span class="o">=</span>colour237 <span class="c1">#bg1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># message infos</span>
</span></span><span class="line"><span class="cl">set-option -g message-style <span class="nv">bg</span><span class="o">=</span>colour239,fg<span class="o">=</span>colour223 <span class="c1"># bg=bg2, fg=fg1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># writing commands inactive</span>
</span></span><span class="line"><span class="cl">set-option -g message-command-style <span class="nv">bg</span><span class="o">=</span>colour239,fg<span class="o">=</span>colour223 <span class="c1"># bg=fg3, fg=bg1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># pane number display</span>
</span></span><span class="line"><span class="cl">set-option -g display-panes-active-colour colour214 <span class="c1">#fg2</span>
</span></span><span class="line"><span class="cl">set-option -g display-panes-colour colour237 <span class="c1">#bg1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># clock</span>
</span></span><span class="line"><span class="cl"><span class="c1">#set-window-option -g clock-mode-colour colour109 #blue</span>
</span></span><span class="line"><span class="cl">set-window-option -g clock-mode-colour colour239 <span class="c1">#blue</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># bell</span>
</span></span><span class="line"><span class="cl">set-window-option -g window-status-bell-style <span class="nv">bg</span><span class="o">=</span>colour167,fg<span class="o">=</span>colour235 <span class="c1"># bg=red, fg=bg</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">## Theme settings mixed with colors (unfortunately, but there is no cleaner way)</span>
</span></span><span class="line"><span class="cl">set-option -g status-justify <span class="s2">&#34;left&#34;</span>
</span></span><span class="line"><span class="cl">set-option -g status-left-style none
</span></span><span class="line"><span class="cl">set-option -g status-left-length <span class="s2">&#34;80&#34;</span>
</span></span><span class="line"><span class="cl">set-option -g status-right-style none
</span></span><span class="line"><span class="cl">set-option -g status-right-length <span class="s2">&#34;80&#34;</span>
</span></span><span class="line"><span class="cl">set-window-option -g window-status-separator <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#################################### config status ######################################</span>
</span></span><span class="line"><span class="cl">set-option -g status-left <span class="s2">&#34;#[fg=colour248, bg=colour241] #S #[fg=colour241, bg=colour237, nobold, noitalics, nounderscore]&#34;</span>
</span></span><span class="line"><span class="cl">set-option -g status-right <span class="s2">&#34;#{prefix_highlight}#[fg=colour239, bg=colour237, nobold, nounderscore, noitalics]#[fg=colour246,bg=colour239] %Y-%m-%d %H:%M #[fg=colour248, bg=colour239, nobold, noitalics, nounderscore]#[fg=colour237, bg=colour248] #h&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">set-window-option -g window-status-current-format <span class="s2">&#34;#[fg=colour237, bg=colour214, nobold, noitalics, nounderscore] #[fg=colour239, bg=colour214] #I #[fg=colour239, bg=colour214, bold] #W #[fg=colour214, bg=colour237, nobold, noitalics, nounderscore]&#34;</span>
</span></span><span class="line"><span class="cl">set-window-option -g window-status-format <span class="s2">&#34;#[fg=colour237,bg=colour239,noitalics]#[fg=colour223,bg=colour239] #I#[fg=colour223, bg=colour239] #W #[fg=colour239, bg=colour237, noitalics]&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>TMUX基本操作</strong></p>
<ul>
<li>tmux 前缀按键：<code>ctrl+b</code></li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># tmux 新建，离开，重连，关闭，列表，重命名</span>
</span></span><span class="line"><span class="cl">tmux new -s &lt;session-name&gt;
</span></span><span class="line"><span class="cl">tmux detach  <span class="c1"># 或者prefixKey + d</span>
</span></span><span class="line"><span class="cl">tmux attach -t &lt;session-name&gt;
</span></span><span class="line"><span class="cl">tmux kill-session -t &lt;session-name&gt;  <span class="c1"># 或者直接exit</span>
</span></span><span class="line"><span class="cl">tmux kill-windows -t &lt;windows-name&gt;
</span></span><span class="line"><span class="cl">tmux ls
</span></span><span class="line"><span class="cl">tmux rename-session -t &lt;old-session-name&gt; &lt;new-session-name&gt;  <span class="c1"># prefixkey + b</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="anaconda-安装">Anaconda 安装</h2>
<p>参考资料：<a href="https://cloud.tencent.com/developer/article/1649008" target="_blank" rel="noopener">如何在 Ubuntu 20.04 上安装 Anaconda</a>
；<a href="https://www.lyytaw.com/%E6%9D%82%E9%A1%B9/oh-my-zsh%E4%B8%BB%E9%A2%98%E6%94%AF%E6%8C%81conda%E8%99%9A%E6%8B%9F%E7%8E%AF%E5%A2%83/#%E8%83%8C%E6%99%AF" target="_blank" rel="noopener">oh-my-zsh主题支持conda虚拟环境</a>
；<a href="https://blog.csdn.net/zw__chen/article/details/100748928" target="_blank" rel="noopener">oh-my-zsh主题显示conda环境名称</a>
</p>
<h3 id="安装">安装</h3>
<p>找到最新的安装包版本：<a href="https://repo.anaconda.com/archive/" target="_blank" rel="noopener">Index of anaconda</a>
 后选择对应的版本安装</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">wget -P /tmp https://repo.anaconda.com/archive/Anaconda3-2021.05-Linux-x86_64.sh</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可选）验证下载版本的正确性：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sha256sum /tmp/Anaconda3-2021.05-Linux-x86_64.sh
</span></span><span class="line"><span class="cl"><span class="c1"># 查看输出的哈希值和对应的archive上的值是一致的</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>安装anaconda</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sh /tmp/Anaconda3-2021.05-Linux-x86_64.sh
</span></span><span class="line"><span class="cl"><span class="c1"># 按照intro应该会执行conda init 等等操作，如果没有我们可以自行执行</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="环境配置">环境配置</h3>
<p>在安装完成后记得执行<code>conda init</code>初始化环境，而针对其他的shell，例如zsh，可以按照以下的流程执行初始化。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 假如当前的shell是zsh</span>
</span></span><span class="line"><span class="cl">bash
</span></span><span class="line"><span class="cl"><span class="nb">source</span> ~/.bashrc
</span></span><span class="line"><span class="cl">conda init zsh
</span></span><span class="line"><span class="cl"><span class="c1"># 退出bash回到zsh</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>关闭conda的命令行提示:</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">conda config --set changeps1 false</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>安装没安装完成的包：</strong></p>
<p><code>sudo apt-get install package --fix-missing</code></p>
<p><strong>更新源：</strong></p>
<p>很多情况下Ubuntu的Source是被屏蔽的，所以我们需要使用国内源进行替代，来提升我们的下载和安装的速度</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># backup the source files in cases that sth wrong</span>
</span></span><span class="line"><span class="cl">sudo cp /etc/apt/sources.list /etc/apt/source.list.bak
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># using sudo to modify or recreate the source.list files</span>
</span></span><span class="line"><span class="cl">sudo nvim /etc/apt/source.list
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># replace the content of it</span>
</span></span><span class="line"><span class="cl"><span class="o">===</span> TSINGHUA <span class="nv">SOURCE</span> <span class="o">===</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># update the source info</span>
</span></span><span class="line"><span class="cl">sudo apt update
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># update the files to varify the speed.</span>
</span></span><span class="line"><span class="cl">sudo apt upgrade</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>实际上换源只要找到对应的ubuntu的发行版，也就是在源链接后面的形式，然后将前面的url改成对应的源即可</p>
<p><a href="https://www.myfreax.com/how-to-change-the-software-source-of-ubuntu-20-04/" target="_blank" rel="noopener">All the source list</a>
；<a href="https://mirrors.tuna.tsinghua.edu.cn/help/ubuntu/" target="_blank" rel="noopener">清华源更新地址</a>
;<a href="https://www.cxyzjd.com/article/amyzhang1234/101555284" target="_blank" rel="noopener">聚合</a>
；<a href="https://mirrors.xjtu.edu.cn/help/ubuntu.html" target="_blank" rel="noopener">XJTU</a>
；<a href="https://developer.aliyun.com/mirror/ubuntu?spm=a2c6h.13651102.0.0.3e221b11newPW7" target="_blank" rel="noopener">Alibaba</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="o">=</span><span class="s">=================== aliyun source ===================</span>
</span></span><span class="line"><span class="cl"><span class="na">deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse</span>
</span></span><span class="line"><span class="cl"><span class="na">deb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse</span>
</span></span><span class="line"><span class="cl"><span class="na">deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse</span>
</span></span><span class="line"><span class="cl"><span class="na">deb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse</span>
</span></span><span class="line"><span class="cl"><span class="na">deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse</span>
</span></span><span class="line"><span class="cl"><span class="na">deb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse</span>
</span></span><span class="line"><span class="cl"><span class="na">deb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse</span>
</span></span><span class="line"><span class="cl"><span class="na">deb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse</span>
</span></span><span class="line"><span class="cl"><span class="na">deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse</span>
</span></span><span class="line"><span class="cl"><span class="na">deb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>其他的相关操作参见Anaconda的相关文档，这里只涉及对应的安装和初始化。</p>
<h2 id="注意事项">注意事项</h2>
<p>@Aiken 2020</p>
<p>本文档主要记录一些Linux下面遇到的问题解决方法：</p>
<h3 id="python环境无法识别">python环境无法识别</h3>
<p>安装完linux以后在bash没法执行conda命令，以及识别不出conda中安装的环境，而从portainer中可以直接启动python的非对等偏差问题。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">source</span>  /opt/conda/bin/activate
</span></span><span class="line"><span class="cl">conda activate base</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>应该是由于没有将conda的自启动加入docker中的自动运作中，所以需要自行对conda 命令进行启动。</p>
<p><strong>solve update：</strong></p>
<p>直接在portainer的terminal中执行如下命令即可一劳永逸</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"> conda init</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="apt-get-找不到包">apt-get 找不到包</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 首先执行apt-get的更新</span>
</span></span><span class="line"><span class="cl"> sudo apt-get update</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="apt-get-varlibdpkglock-frontend">apt-get /var/lib/dpkg/lock-frontend</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo rm /var/lib/dpkg/lock-frontend
</span></span><span class="line"><span class="cl">sudo rm /var/lib/dpkg/lock
</span></span><span class="line"><span class="cl">sudo rm /var/cache/apt/archives/lock</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>不知道哪个真正起了作用，都试试把</p>
<h3 id="chsh-pam-authentication-failure">chsh: PAM: Authentication failure</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sh</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">code /etc/passwd
</span></span><span class="line"><span class="cl"><span class="c1"># 里面可能有一些配置出现了问题，包括 bin/bash 漏了前面的斜杠这种</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="nvcc-command-not-found">NVCC command not found</h3>
<p>在安装CUDA后还是找不到命令的话，可以去以下地址找一下对应的cuda文件是否存在</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ls -l /usr/local/cuda
</span></span><span class="line"><span class="cl"><span class="c1"># 如果存在的话，将cuda的路径导入到bashrc中</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">export LD_LIBRARY_PATH</span><span class="o">=</span><span class="s">/usr/local/cuda/lib64:$LD_LIBRARY_PATH</span>
</span></span><span class="line"><span class="cl"><span class="na">export PATH</span><span class="o">=</span><span class="s">/usr/local/cuda/bin:$PATH</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="gdbuserror">GDBus.Error:</h3>
<blockquote>
<p>GDBus.Error:org.freedesktop.DBus.Error.Spawn.ExecFailed: Failed to execute program org.freedesktop.PackageKit: Permission denied</p>
</blockquote>
<p>其实就是两行命令来修复 dbus 文件的执行权限：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">Sudo chown root:messagebus /usr/lib/dbus-1.0/dbus-daemon-launch-helper
</span></span><span class="line"><span class="cl">Sudo chmod <span class="m">4754</span> /usr/lib/dbus-1.0/dbus-daemon-launch-helper</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>————————————————
版权声明：本文为 CSDN 博主「Main(happy)」的原创文章，遵循 CC 4.0 BY-SA 版权协议，转载请附上原文出处链接及本声明。
原文链接： <a href="https://blog.csdn.net/baidu_31628641/article/details/108586804" target="_blank" rel="noopener">https://blog.csdn.net/baidu_31628641/article/details/108586804</a>
</p>
<h3 id="syntax-error--unexpected">Syntax error: &ldquo;(&rdquo; unexpected</h3>
<p>该错误可能由于 Ubuntu 本身默认的 sh 指定的为 dash，而我们通常编写的脚本都是基于 Bash 的，因此这里介绍一下切换 sh 的命令</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 查看当前默认的sh</span>
</span></span><span class="line"><span class="cl">ls -l /bin/sh
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 切换为bash，在弹出的对话框选择no则切换为bash，yes则为dash</span>
</span></span><span class="line"><span class="cl">sudo dpkg-reconfigure dash </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>切换完成后使用 sh 执行脚本应该不会出现上述问题了，验证的话也可以使用 bash 执行脚本。</p>
]]></content:encoded>
    </item>
    <item>
      <title>Data Augmentation</title>
      <link>https://aikenh.cn/posts/dataaugmentation/</link>
      <pubDate>Sun, 28 Nov 2021 06:24:20 +0000</pubDate>
      <guid>https://aikenh.cn/posts/dataaugmentation/</guid>
      <description>&lt;p&gt;intergrate with those augmentation method.&lt;/p&gt;
&lt;p&gt;this doc will&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Record those theory and the effect after transformation&lt;/li&gt;
&lt;li&gt;Show the codes for ez use&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And the complete &lt;code&gt;.py&lt;/code&gt; will be intergrate in my classification pipeline&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;reference&lt;/strong&gt; below:arrow_down_small:, if use them,start it for respect for his work.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/aleju/imgaug#documentation&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;aleju/imgaug&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;:star:&lt;a href=&#34;https://github.com/albumentations-team/albumentations&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;albumentations-team/albumentations: &lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pytorch.org/vision/stable/transforms.html#transforms-on-pil-image-and-torch-tensor&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;torchvision&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pillow.readthedocs.io/en/stable/reference/ImageEnhance.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;PIL/ImageEnhance CCBS&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;opencv&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;principle&#34;&gt;Principle&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Principle 1&lt;/strong&gt; of coding: Don’t reinvent the wheel unless it’s needed&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;具体而言，仅在函数的拓展性较差，无法对其定制化，满足我们的日常需求的时候，我们会自行编写函数从而满足我们的需求，否则我们直接引用已知的库，提升我们的实现效率。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Principle 2&lt;/strong&gt; of coding 图像增强的两种使用方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;做全集的增强后存储在本地，然后通过&lt;strong&gt;随机&lt;/strong&gt;载入或者按一定&lt;strong&gt;batch&lt;/strong&gt;的载入来实现我们增强的作用，（or contrasive），这种方式实际上是使用空间来换时间，由于处理是一次性的，所以如果空间充足的话，是更为充足的方式。&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>intergrate with those augmentation method.</p>
<p>this doc will</p>
<ul>
<li>Record those theory and the effect after transformation</li>
<li>Show the codes for ez use</li>
</ul>
<p>And the complete <code>.py</code> will be intergrate in my classification pipeline</p>
<p><strong>reference</strong> below:arrow_down_small:, if use them,start it for respect for his work.</p>
<ul>
<li><a href="https://github.com/aleju/imgaug#documentation" target="_blank" rel="noopener">aleju/imgaug</a>
</li>
<li>:star:<a href="https://github.com/albumentations-team/albumentations" target="_blank" rel="noopener">albumentations-team/albumentations: </a>
</li>
<li><a href="https://pytorch.org/vision/stable/transforms.html#transforms-on-pil-image-and-torch-tensor" target="_blank" rel="noopener">torchvision</a>
</li>
<li><a href="https://pillow.readthedocs.io/en/stable/reference/ImageEnhance.html" target="_blank" rel="noopener">PIL/ImageEnhance CCBS</a>
</li>
<li>opencv</li>
</ul>
<h2 id="principle">Principle</h2>
<p><strong>Principle 1</strong> of coding: Don’t reinvent the wheel unless it’s needed</p>
<ul>
<li>具体而言，仅在函数的拓展性较差，无法对其定制化，满足我们的日常需求的时候，我们会自行编写函数从而满足我们的需求，否则我们直接引用已知的库，提升我们的实现效率。</li>
</ul>
<p><strong>Principle 2</strong> of coding 图像增强的两种使用方式：</p>
<ul>
<li>
<p>做全集的增强后存储在本地，然后通过<strong>随机</strong>载入或者按一定<strong>batch</strong>的载入来实现我们增强的作用，（or contrasive），这种方式实际上是使用空间来换时间，由于处理是一次性的，所以如果空间充足的话，是更为充足的方式。</p>
</li>
<li>
<p>动态的在线增强：这种方式比较消耗io和cpu，不推荐，但是如果本地的空间不够，就只能采用这种方式了。</p>
</li>
</ul>
<p><strong>Principle 3</strong> of saving 如果我们要存储本地副本的话，推荐的存储格式和方式</p>
<ul>
<li>
<p><strong>文件格式</strong>：<code>npz</code> 由于多种增强，实际上这种方式还蛮适合使用<code>npz</code>格式作为我们的存储，这种既保留了对应的<code>np</code>还可以保留对应的字典信息，此外这种方式的存取速度也不算慢，（相较之下好像没有特别突出的一种格式）</p>
</li>
<li>
<p><strong>路径格式</strong>：<code>imagenet</code>也就是对应的train-class-data的层级关系，通过这种约定俗称的存储关系我们得以在我们框架中的dataset格式方便读入</p>
</li>
</ul>
<h2 id="pilcv2skimage的选择">PIL，CV2，SkImage的选择</h2>
<p><a href="https://www.jianshu.com/p/cfca9c4338e7" target="_blank" rel="noopener">pytorch图像的加载/读取方式</a>
 | <a href="https://zhuanlan.zhihu.com/p/357069891" target="_blank" rel="noopener">cv2、PIL、matplotlib</a>
</p>
<p>在这里讲解三个模块之间的基本区别和其中的选择，目前希望将已有的算法从PIL转向CV2，后续也会添加一下三个模块对于Torch的适配性等等</p>
<h3 id="数据读写">数据读写</h3>
<p>基于下列的代码和注释给出相应的之间的区别，通过这些区别我们可以知道几乎所有的格式在使用的时候都是需要对应的转换的，</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">cv2</span>
</span></span><span class="line"><span class="cl"><span class="n">img</span>  <span class="o">=</span> <span class="n">cv2</span><span class="o">.</span><span class="n">imread</span><span class="p">(</span><span class="s1">&#39;lena.png&#39;</span><span class="p">)</span> <span class="c1"># numpy格式，HWC，【0，255】，BGR</span>
</span></span><span class="line"><span class="cl"><span class="n">img</span> <span class="o">=</span> <span class="n">cv2</span><span class="o">.</span><span class="n">cvtColor</span><span class="p">(</span><span class="n">img</span><span class="p">,</span><span class="n">cv2</span><span class="o">.</span><span class="n">COLOR_BGR2RGB</span><span class="p">)</span> <span class="c1"># 除了最下方的转换方式外也可以通过这种方式进行转换</span>
</span></span><span class="line"><span class="cl"><span class="n">cv2</span><span class="o">.</span><span class="n">imwrite</span><span class="p">(</span><span class="s1">&#39;lena.jpg&#39;</span><span class="p">,</span> <span class="n">img</span><span class="p">)</span> <span class="c1"># img 需为BGR格式的numpy array</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">PIL</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">PIL</span> <span class="kn">import</span> <span class="n">Image</span>
</span></span><span class="line"><span class="cl"><span class="n">img</span> <span class="o">=</span> <span class="n">Image</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s1">&#39;lena.png&#39;</span><span class="p">)</span> <span class="c1"># PIL格式，RGB，【0，255】</span>
</span></span><span class="line"><span class="cl"><span class="n">img</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">img</span><span class="p">)</span> <span class="c1"># 转换为numpy格式, HWC</span>
</span></span><span class="line"><span class="cl"><span class="n">Img</span><span class="o">.</span><span class="n">fromarray</span><span class="p">(</span><span class="n">img</span><span class="p">)</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s1">&#39;lena.png&#39;</span><span class="p">)</span> <span class="c1"># x需要转换为PIL.Image格式才能保存</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">skimage</span> <span class="kn">import</span> <span class="n">io</span> 
</span></span><span class="line"><span class="cl"><span class="n">img</span> <span class="o">=</span> <span class="n">io</span><span class="o">.</span><span class="n">imread</span><span class="p">(</span><span class="s1">&#39;lena.png&#39;</span><span class="p">)</span> <span class="c1"># numpy 格式， RGB，【0，1】 HWC</span>
</span></span><span class="line"><span class="cl"><span class="n">io</span><span class="o">.</span><span class="n">imsave</span><span class="p">(</span><span class="s1">&#39;lena.jpg&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
</span></span><span class="line"><span class="cl"><span class="n">img</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">imread</span><span class="p">(</span><span class="s1">&#39;lena.png&#39;</span><span class="p">)</span> <span class="c1"># numpy 格式，HWC [0,255] RGB</span>
</span></span><span class="line"><span class="cl"><span class="n">plt</span><span class="o">.</span><span class="n">imsave</span><span class="p">(</span><span class="s1">&#39;lena.jpg&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># BGR 转换 RGB, 转回来也是一样的操作 </span>
</span></span><span class="line"><span class="cl"><span class="n">img_rgb</span> <span class="o">=</span> <span class="n">img_bgr</span><span class="p">[:,:,::</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>基于上述的代码，我们可以总结出：</p>
<p>当我们使用matplotlib的时候</p>
<ul>
<li>当我们用cv2读取图像的时候若要进行matplotlib的展示，我们需要对其做<code>bgr2rgb</code>的转换，PIL则需要做到numpy的转换，skimage考虑归一化方面的问题</li>
</ul>
<p>当我们要使用tensror格式的时候</p>
<ul>
<li>
<p>我们需要对cv2转换成RGB</p>
</li>
<li>
<p>对三个方法都是用<code>transpose</code>或者类似的方法转换到CHW</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">torch</span> 
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
</span></span><span class="line"><span class="cl"><span class="n">torch_img</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">from_numpy</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">transpose</span><span class="p">(</span><span class="n">img</span><span class="p">,(</span><span class="mi">2</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">)))</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
</ul>
<h2 id="简单图像增强">简单图像增强</h2>
<p>在这里由于opencv更为强大且全面，我们将框架转移到opencv中进行图像增强处理，于是本章节会主要介绍<code>opencv</code>, <code>torchvision中的图像增强，同时也会对</code>pillow<code>,</code>skimage`进行简单的介绍。</p>
<h3 id="torchvision">TorchVision</h3>
<p>torchvision的使用实际上是最简单便捷的，为了协调统一，该类变换我们在totensor后进行使用，接在其他所有变换的后面，实际上有一些变换是可以获取参数的，要调用的对应函数我们可以在对应<a href="https://pytorch.org/vision/stable/transforms.html#scriptable-transforms" target="_blank" rel="noopener">文档</a>
中查询</p>
<p>**随机机制：**现已向后兼容torch</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 随机种子采用torch</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">torch</span> 
</span></span><span class="line"><span class="cl"><span class="n">torch</span><span class="o">.</span><span class="n">manual_seed</span><span class="p">(</span><span class="mi">17</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># KEY FUNCTION: 给一个transformers加上概率，以一定的概率执行该操作</span>
</span></span><span class="line"><span class="cl"><span class="n">transformers</span><span class="o">.</span><span class="n">RandomApply</span><span class="p">(</span><span class="n">transforms</span><span class="p">,</span><span class="n">p</span><span class="o">=</span><span class="mf">0.5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Key Function：从给定的一系列transforms中选一个进行操作</span>
</span></span><span class="line"><span class="cl"><span class="n">transformers</span><span class="o">.</span><span class="n">RandomChoice</span><span class="p">(</span><span class="n">transforms</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>由于存在<code>randomapply</code>这个函数，所以实际上我们在调用变换的时候，我们可以用prefix random去搜补全，如果没有的话，也可以使用<code>RandomApply</code>来手动赋予随机性。</p>
<p>**组合机制：**同时使用多种变换，这种方法将一组强关联的变换进行组合，简化后续的使用，但是对于我们如果需要做多种增强的话，实际上并不是一个合适的方式。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># a simple example for torchvision&#39;s transformer</span>
</span></span><span class="line"><span class="cl"><span class="n">transform</span> <span class="o">=</span> <span class="n">transforms</span><span class="o">.</span><span class="n">Compose</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">	<span class="n">transforms</span><span class="o">.</span><span class="n">CenterCrop</span><span class="p">(</span><span class="mi">10</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">	<span class="n">transforms</span><span class="o">.</span><span class="n">PILtoTensor</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">	<span class="n">transforms</span><span class="o">.</span><span class="n">ConvertImageDtype</span><span class="p">(</span><span class="n">torch</span><span class="o">.</span><span class="n">float</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">])</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>常见的一些增强：</strong><a href="https://www.bilibili.com/read/cv7313702/" target="_blank" rel="noopener">列在下面</a>
</p>
<ul>
<li>
<p>裁剪系列：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># cental crop</span>
</span></span><span class="line"><span class="cl"><span class="n">transforms</span><span class="o">.</span><span class="n">CenterCrop</span><span class="p">(</span><span class="n">size</span><span class="p">),</span> 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># five corners and the cental crop</span>
</span></span><span class="line"><span class="cl"><span class="n">transforms</span><span class="o">.</span><span class="n">FiveCrop</span><span class="p">(</span><span class="n">size</span><span class="p">),</span> 
</span></span><span class="line"><span class="cl"><span class="k">lambda</span><span class="p">(</span><span class="k">lambda</span> <span class="n">crops</span><span class="p">:</span> <span class="n">torch</span><span class="o">.</span><span class="n">stack</span><span class="p">[</span><span class="n">ToTensor</span><span class="p">()(</span><span class="n">crop</span><span class="p">)</span> <span class="k">for</span> <span class="n">crop</span> <span class="ow">in</span> <span class="n">crops</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 随机裁剪到对应的尺寸，</span>
</span></span><span class="line"><span class="cl"><span class="n">transforms</span><span class="o">.</span><span class="n">RandomCrop</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="n">padding</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">pad_if_needed</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">fill</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">padding_mode</span><span class="o">=</span><span class="s1">&#39;constant&#39;</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 随机裁剪后resize到指定的尺寸</span>
</span></span><span class="line"><span class="cl"><span class="n">transforms</span><span class="o">.</span><span class="n">RandomResizedCropsize</span><span class="p">,</span> <span class="n">scale</span><span class="o">=</span><span class="p">(</span><span class="mf">0.08</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">),</span> <span class="n">ratio</span><span class="o">=</span><span class="p">(</span><span class="mf">0.75</span><span class="p">,</span> <span class="mf">1.33</span><span class="p">),</span> <span class="n">interpolation</span><span class="o">=&lt;</span><span class="n">InterpolationMode</span><span class="o">.</span><span class="n">BILINEAR</span><span class="p">:</span> <span class="s1">&#39;bilinear&#39;</span><span class="o">&gt;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Padding 无需多言</span>
</span></span><span class="line"><span class="cl"><span class="n">transformers</span><span class="o">.</span><span class="n">Pad</span><span class="p">(</span><span class="n">padding</span><span class="p">,</span><span class="n">fill</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span><span class="n">padding_mode</span><span class="o">=</span><span class="s1">&#39;constant&#39;</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>色彩变换增强</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 色彩抖动,随机改变亮度对比度饱和度和色调</span>
</span></span><span class="line"><span class="cl"><span class="n">transforms</span><span class="o">.</span><span class="n">Colorjitter</span><span class="p">(</span><span class="n">brightness</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">contrast</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">saturation</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">hue</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 图像转换为灰度</span>
</span></span><span class="line"><span class="cl"><span class="n">transforms</span><span class="o">.</span><span class="n">grayscale</span><span class="p">(</span><span class="n">num_output_channel</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>几何变换增强</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 仿射变换</span>
</span></span><span class="line"><span class="cl"><span class="n">transformers</span><span class="o">.</span><span class="n">RandomAffine</span><span class="p">(</span><span class="n">degrees</span><span class="p">,</span> <span class="n">translate</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">scale</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">shear</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">interpolation</span><span class="o">=&lt;</span><span class="n">InterpolationMode</span><span class="o">.</span><span class="n">NEAREST</span><span class="p">:</span> <span class="s1">&#39;nearest&#39;</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">fill</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">fillcolor</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">resample</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 可以通过以下函数获取变换矩阵</span>
</span></span><span class="line"><span class="cl"><span class="n">get_params</span><span class="p">(</span><span class="n">degrees</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">float</span><span class="p">],</span> <span class="n">translate</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">List</span><span class="p">[</span><span class="nb">float</span><span class="p">]],</span> <span class="n">scale_ranges</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">List</span><span class="p">[</span><span class="nb">float</span><span class="p">]],</span> <span class="n">shears</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">List</span><span class="p">[</span><span class="nb">float</span><span class="p">]],</span> <span class="n">img_size</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">int</span><span class="p">])</span> <span class="err">→</span> <span class="n">Tuple</span><span class="p">[</span><span class="nb">float</span><span class="p">,</span> <span class="n">Tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">],</span> <span class="nb">float</span><span class="p">,</span> <span class="n">Tuple</span><span class="p">[</span><span class="nb">float</span><span class="p">,</span> <span class="nb">float</span><span class="p">]]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">transforms</span><span class="o">.</span><span class="n">RandomHorizontalFlip</span><span class="p">(</span><span class="n">p</span><span class="o">=</span><span class="mf">0.5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">transforms</span><span class="o">.</span><span class="n">RandomPerspective</span><span class="p">(</span><span class="n">distortion_scale</span><span class="o">=</span><span class="mf">0.5</span><span class="p">,</span> <span class="n">p</span><span class="o">=</span><span class="mf">0.5</span><span class="p">,</span> <span class="n">interpolation</span><span class="o">=&lt;</span><span class="n">InterpolationMode</span><span class="o">.</span><span class="n">BILINEAR</span><span class="p">:</span> <span class="s1">&#39;bilinear&#39;</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">fill</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">RandomResizedCrop</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
</ul>
<h3 id="opencv">OpenCV</h3>
<h4 id="install">Install</h4>
<p>Ubuntu：安装opencv的python版本</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">apt-get -y python3-opencv
</span></span><span class="line"><span class="cl">pip install opencv-python</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="usage">Usage</h4>
<p>这一部分可能主要还是对OpenCV基础使用方式的介绍，至于数据增强方面，上面有一个库已经集成了很大一部分图像增强的操作，且在效率上也有了很高的优化和证实，简单的使用方式如下。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="kn">import</span> <span class="nn">albumentations</span> <span class="k">as</span> <span class="nn">A</span>
</span></span><span class="line"><span class="cl"><span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">os</span><span class="o">.</span><span class="n">system</span><span class="p">(</span><span class="s2">&#34;pip install - U albumentations&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="kn">import</span> <span class="nn">albumentations</span> <span class="k">as</span> <span class="nn">A</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">cv2</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Declare an augmentation pipeline</span>
</span></span><span class="line"><span class="cl"><span class="n">transform</span> <span class="o">=</span> <span class="n">A</span><span class="o">.</span><span class="n">Compose</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">    <span class="n">A</span><span class="o">.</span><span class="n">RandomCrop</span><span class="p">(</span><span class="n">width</span><span class="o">=</span><span class="mi">256</span><span class="p">,</span> <span class="n">height</span><span class="o">=</span><span class="mi">256</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">A</span><span class="o">.</span><span class="n">HorizontalFlip</span><span class="p">(</span><span class="n">p</span><span class="o">=</span><span class="mf">0.5</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">A</span><span class="o">.</span><span class="n">RandomBrightnessContrast</span><span class="p">(</span><span class="n">p</span><span class="o">=</span><span class="mf">0.2</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Read an image with OpenCV and convert it to the RGB colorspace</span>
</span></span><span class="line"><span class="cl"><span class="n">image</span> <span class="o">=</span> <span class="n">cv2</span><span class="o">.</span><span class="n">imread</span><span class="p">(</span><span class="s2">&#34;image.jpg&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">image</span> <span class="o">=</span> <span class="n">cv2</span><span class="o">.</span><span class="n">cvtColor</span><span class="p">(</span><span class="n">image</span><span class="p">,</span> <span class="n">cv2</span><span class="o">.</span><span class="n">COLOR_BGR2RGB</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Augment an image</span>
</span></span><span class="line"><span class="cl"><span class="n">transformed</span> <span class="o">=</span> <span class="n">transform</span><span class="p">(</span><span class="n">image</span><span class="o">=</span><span class="n">image</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">transformed_image</span> <span class="o">=</span> <span class="n">transformed</span><span class="p">[</span><span class="s2">&#34;image&#34;</span><span class="p">]</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>下面我们会讲一些opencv中的简单使用方式：</p>
<p><a href="https://www.cnblogs.com/silence-cho/p/10926248.html" target="_blank" rel="noopener">(一)OpenCV-Python学习—基础知识 - silence_cho - 博客园 (cnblogs.com)</a>
</p>
<h3 id="pillow">Pillow</h3>
<p>Using PIL do <a href="https://zhuanlan.zhihu.com/p/74053773" target="_blank" rel="noopener">some augmentation</a>
</p>
<ol>
<li>CCBS： color，contrast，brightness，shapen</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># way1：PIL</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">PIL</span> <span class="kn">import</span> <span class="n">ImageEnhance</span>
</span></span><span class="line"><span class="cl"><span class="n">ccbs_img</span> <span class="o">=</span> <span class="n">ImageEnhance</span><span class="o">.</span><span class="n">Color</span><span class="p">(</span><span class="n">img</span><span class="p">)</span><span class="o">.</span><span class="n">enhance</span><span class="p">(</span><span class="n">factor1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="o">...</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="2">
<li>
<p>Blur，Detail，Edge_Enhance，Smooth，Sharpen…</p>
<p>自行在文档中找到对应的方法，实际上不是很多</p>
</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">PIL</span> <span class="kn">import</span> <span class="n">Image</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">PIL.ImageFillter</span> <span class="kn">import</span> <span class="n">SMOOTH</span><span class="p">,</span><span class="n">BLUR</span>
</span></span><span class="line"><span class="cl"><span class="n">img</span> <span class="o">=</span> <span class="n">Image</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">image_pah</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">img_1</span> <span class="o">=</span> <span class="n">img</span><span class="o">.</span><span class="n">filtter</span><span class="p">(</span><span class="n">BLUR</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">img_2</span> <span class="o">=</span> <span class="n">img</span><span class="o">.</span><span class="n">filtter</span><span class="p">(</span><span class="n">SMOOTH</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="skimage">SkImage</h3>
<p>&hellip;</p>
<h2 id="混合图像增强for-ml">混合图像增强（For ML）</h2>
<p>==ALL in one 不是什么好点子==
为了对Machine Learning中的任务进行图像增强任务，我们在过程中可能会使用一些Github Repo，主要可能就是albumation，在进行图像增强和数据混合的过程中，我们会遇到的问题包括：</p>
<ul>
<li>PIL和NP，Tensor的三者格式不对应的关系</li>
<li>Channel混杂的关系</li>
<li>调用transformer的形式不统一的问题</li>
</ul>
<p>为此我们特地开了这个专题，介绍一下使用的方式，以及使我们在后续的使用过程中注意最终转换到datalist中最好采用统一的存储形式</p>
<ol>
<li>path（load by cv or pil，st np）</li>
<li>data （np（else），tensor（cuda）for instant use）</li>
</ol>
<p>以此来规范我们的dataset，and sampler or mixer</p>
<p>我们可以尝试使用如下的方式来进行transformer的管理操作，此外如果我们要用的是纯粹的数据增强而不是用来dataloader的transformer，我们就不要用这个逻辑去做，我们直接集成Augmentation就好了
ch</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">mytransformer</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">	<span class="c1"># if augs is not none we need to add ToPIL to get the right data type</span>
</span></span><span class="line"><span class="cl">	<span class="k">def</span> <span class="nf">get_transformers</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">		<span class="bp">self</span><span class="o">.</span><span class="n">transformer</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="s1">&#39;augs&#39;</span><span class="p">:</span> <span class="n">Augs</span><span class="o">.</span><span class="n">Compose</span><span class="p">([]),</span>
</span></span><span class="line"><span class="cl">			<span class="s1">&#39;trans&#39;</span><span class="p">:</span> <span class="n">transformers</span><span class="o">.</span><span class="n">Compose</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">				<span class="n">tranformers</span><span class="o">.</span><span class="n">ToPIL</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">				<span class="o">...</span>
</span></span><span class="line"><span class="cl">			<span class="p">]),</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1"># then we using k-v pair to do all my transformer, </span>
</span></span><span class="line"><span class="cl">	<span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="n">img</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">		<span class="k">for</span> <span class="n">k</span><span class="p">,</span><span class="n">v</span> <span class="ow">in</span> <span class="n">transformer</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">			<span class="n">img</span> <span class="o">=</span> <span class="n">transformer</span><span class="p">[</span><span class="s1">&#39;augs&#39;</span><span class="p">](</span><span class="n">image</span><span class="o">=</span><span class="n">img</span><span class="p">)[</span><span class="s1">&#39;image&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">			<span class="n">img</span> <span class="o">=</span> <span class="n">transformer</span><span class="p">[</span><span class="s1">&#39;trans&#39;</span><span class="p">](</span><span class="n">img</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="n">img</span>
</span></span><span class="line"><span class="cl">	</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="特殊图像增强">特殊图像增强</h2>
<p>&hellip;</p>
]]></content:encoded>
    </item>
    <item>
      <title>Hard Task Sampling</title>
      <link>https://aikenh.cn/posts/hardtask/</link>
      <pubDate>Sun, 28 Nov 2021 06:24:17 +0000</pubDate>
      <guid>https://aikenh.cn/posts/hardtask/</guid>
      <description>困难样本再采样</description>
      <content:encoded><![CDATA[<h1 id="trickhard-task">Trick：Hard Task</h1>
<p>思路来源于Meta-Tranfer-Learning，基本思路是在Meta-Learning的每一次Meta-Test的时候，会从预训练错误率比较高的Task中再次采样，增加那些task的训练次数。也就是难题多做的策略。</p>
<h2 id="基本思路">基本思路</h2>
<h3 id="对比adaboost">对比Adaboost</h3>
<p>这样的思路其实和AdaBoost的想法是有一定的异曲同工之妙的，或者说其实就是AdaBoost的思路：</p>
<p><strong>Adaboost</strong></p>
<p><a href="https://zhuanlan.zhihu.com/p/39972832" target="_blank" rel="noopener">参考笔记</a>
，从该笔记中我们可以看到，AdaBoost的基本思路如下：</p>
<blockquote>
<p>Boosting算法的工作机制是首先从训练集用初始权重训练出一个弱学习器1，根据弱学习的学习误差率表现来<strong>更新训练样本的权重</strong>，使得之前弱学习器1学习误差率高的训练样本点的权重变高，使得这些<strong>误差率高的点</strong>在后面的弱学习器2中<strong>得到更多的重视</strong>。然后基于调整权重后的训练集来训练弱学习器2.，如此重复进行，直到弱学习器数达到事先指定的数目T，最终将这T个弱学习器通过集合策略进行整合，得到最终的强学习器.</p>
</blockquote>
<p>和Meta-Transfer-Learning对比一下，我们可以发现，这个方法实际上就是讲Transfer Learning的与训练网络当成弱学习器1，然后通过弱学习器1的训练样本权重，来增大Hard-Task的配比（也就是增加任务的权重）完全一致。</p>
<h3 id="具体实现">具体实现</h3>
<p>实现上主要是，样本sample的过程，就是如何在进行参数选择后和原本的Dataloader，结合起来。在这里我们主要参考MTL中的方法，进行网络的构建处理。</p>
<p>第一部分：<strong>sampler构建</strong>，为了后续Dataloader中进行数据的采样，需要构建一个这样的sampler，关键在于index的对应关系，以及最后输出的是index的集合。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">torch</span> 
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 注意的点，我们需要确定我们batch数目，cls数目和每次每个cls选出多少个数据per</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 紧接着定义一个sample，sample输出的是对应原dataset中的数据的index，</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">CatagoriesSampler</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">label</span><span class="p">,</span> <span class="n">n_batch</span><span class="p">,</span> <span class="n">n_cls</span><span class="p">,</span> <span class="n">n_per</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">n_batch</span> <span class="o">=</span> <span class="n">n_batch</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">n_cls</span> <span class="o">=</span> <span class="n">n_cls</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">n_per</span> <span class="o">=</span> <span class="n">n_per</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="n">label</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">label</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 根据不同的label输入情况，我们可可能需要找到每个label对应的样本的index，将其整合在一起。如下（option）</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">m_idx</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">max</span><span class="p">(</span><span class="n">label</span><span class="p">)</span><span class="o">+</span><span class="mi">1</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">idx</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">argwhere</span><span class="p">(</span><span class="n">label</span><span class="o">==</span><span class="n">i</span><span class="p">)</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">idx</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">from_numpy</span><span class="p">(</span><span class="n">idx</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="bp">self</span><span class="o">.</span><span class="n">m_idx</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">idx</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">   
</span></span><span class="line"><span class="cl">	<span class="k">def</span> <span class="fm">__len__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 要注意一下这里数据的长度是根据我们要输出的batch数目决定的</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">n_batch</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__iter__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 直接定义每次采样的时候的batch输出</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">i_batch</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">n_batch</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">batch</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">            <span class="n">classes</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">randperm</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">m_idx</span><span class="p">))[:</span><span class="bp">self</span><span class="o">.</span><span class="n">n_cls</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">            <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">classes</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="c1"># 随机选择出的类标签</span>
</span></span><span class="line"><span class="cl">                <span class="n">l</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">m_idx</span><span class="p">[</span><span class="n">c</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">                <span class="c1"># 随机选择样本</span>
</span></span><span class="line"><span class="cl">                <span class="n">random_pos</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">randperm</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">l</span><span class="p">))[:</span><span class="bp">self</span><span class="o">.</span><span class="n">n_per</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">                <span class="n">batch</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">l</span><span class="p">[</span><span class="n">random_pos</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">            <span class="c1"># stack t and reshape的作用👇</span>
</span></span><span class="line"><span class="cl">            <span class="c1"># stack 变成n_cls * n_per , t转置，reshape（-1）变成行向量</span>
</span></span><span class="line"><span class="cl">            <span class="n">batch</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">stack</span><span class="p">(</span><span class="n">batch</span><span class="p">)</span><span class="o">.</span><span class="n">t</span><span class="p">()</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">yield</span> <span class="n">batch</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>第二部分：直接调用部分</p>
<p>其实就是很简单的Dataloader中就有这个参数设置，只需要定义好sampler就没什么太大的问题了。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="bp">self</span><span class="o">.</span><span class="n">trainset</span> <span class="o">=</span> <span class="n">Dataset</span><span class="p">(</span><span class="s1">&#39;train&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="bp">self</span><span class="o">.</span><span class="n">train_sampler</span> <span class="o">=</span> <span class="n">CategoriesSampler</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="bp">self</span><span class="o">.</span><span class="n">trainset</span><span class="o">.</span><span class="n">label</span><span class="p">,</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">num_batch</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">way</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">    <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">shot</span><span class="o">+</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">train_query</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="bp">self</span><span class="o">.</span><span class="n">train_loader</span> <span class="o">=</span> <span class="n">DataLoader</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">dataset</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">trainset</span><span class="p">,</span><span class="n">batch_sampler</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">train_sampler</span><span class="p">,</span> <span class="n">num_workers</span><span class="o">=</span><span class="mi">8</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">    <span class="n">pin_memory</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 关键的地方在于最后一样的batch_sampler，这个在pytorch的dataload文档中分析过，就是每次会按这个规则在这里采样数据出来，一起训练。</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>第三部分：Hard-Task的选取</p>
<p>以什么形式或者标准来对Hard-Task进行选择，以及构建这个label list，因为我们知道，很多时候dataloader是不输出index的。</p>
<p>本文作者tmd直接偷懒，直接用数据集的label，也就是根本就不是Hard-Task的处理</p>
]]></content:encoded>
    </item>
    <item>
      <title>并行训练</title>
      <link>https://aikenh.cn/posts/%E5%B9%B6%E8%A1%8C%E8%AE%AD%E7%BB%83%E7%9A%84%E7%90%86%E8%A7%A3/</link>
      <pubDate>Sun, 28 Nov 2021 02:20:31 +0000</pubDate>
      <guid>https://aikenh.cn/posts/%E5%B9%B6%E8%A1%8C%E8%AE%AD%E7%BB%83%E7%9A%84%E7%90%86%E8%A7%A3/</guid>
      <description>Help to understand the data or model parallel in PT</description>
      <content:encoded><![CDATA[<p><a href="https://lilianweng.github.io/lil-log/2021/09/24/train-large-neural-networks.html" target="_blank" rel="noopener">How to Train Really Large Models on Many GPUs? (lilianweng.github.io)</a>
</p>
<p>对于浮点运算，模型参数的存储和中间计算输出（梯度和优化器状态）的存储的在 GPU 内存上的大量需求使得我们需要并行化，下面我们参考一些常用的并行化范式：</p>
<h2 id="数据并行策略"><strong>数据并行</strong>策略：</h2>
<p>在Multi-GPUs上Duplicate模型，然后分别feed数据，进行运算，每个batch同步或者异步的进行多卡间的梯度传递和模型同步。</p>
<p>同步可能会导致每个batch需要停止训练，异步则是可能会使用陈旧的梯度进行一段时间的训练，增加了计算时间。</p>
<p>而在PT1.5以来，使用一种中间的方式：每隔x次迭代，进行多卡间的全局同步梯度一次，使用这种梯度积累的策略，根据计算图来进行计算和通信调度的优化，提高吞吐量。</p>
<h2 id="模型并行范式"><strong>模型并行</strong>范式：</h2>
<p>是为了解决单模型过大无法存储在单一的Node上的问题，但是这样会有GPU间的顺序依赖，虽然减少了内存的占用和计算量，但是这种IO的需求导致计算资源的利用率严重不足。</p>
<p>在这种pipeline中，就存在利用率的bubble，也就是空白的部分</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211111171158.png">
    <img alt="image-20211111165251900" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211111171158.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211111171158.png" style="display: block; margin: 0 auto;"
      alt="image-20211111165251900"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="pipeline并行策略"><strong>Pipeline并行</strong>策略：</h2>
<p>混合模型和数据并行的策略，来减少低效时间的泡沫，也就是，将一个batch切分成多个小batch，然后分发到每个node上，减少相应的等待时间，只要我们对计算量和运行速度有合理的把握，就能极大的降低这个inefficient time bubbles. 多个mini-batch的梯度聚集起来最后同步更新. 最有情况下甚至可以忽略气泡的开销</p>
<div>
$$ 
1- \frac{2md}{(2m+2(d-1))d} = \frac{d-1}{m+d-1}
 $$
</div>
<p>m个mini-batch和d个分布, bubble的比例将如上述所示</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211111170038.png">
    <img alt="image-20211111170037307" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211111170038.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211111170038.png" style="display: block; margin: 0 auto;"
      alt="image-20211111170037307"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>这种方式能实现吞吐量和设备数量的几乎线性加速, 但是如果参数模型不能均匀的分布的话, 她并不总是能保证.</p>
<p>pipedream下面的这种方法, 虽然没有在最后进行全局的梯度同步, 可能会有之前提到的异步并行的问题, 使用不同的模型权重, 但作者也提出了一些相应的解决方案, 包括权重存储和垂直同步等等方法.</p>
<p>详细的需要的时候对原文进行参考.</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211111170504.png">
    <img alt="image-20211111170503212" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211111170504.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211111170504.png" style="display: block; margin: 0 auto;"
      alt="image-20211111170503212"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>后续还有两个对其的不同设置的改进<code> *PipeDream-flush*</code> | <code>*PipeDream-2BW*</code></p>
<h2 id="tensor并行范式"><strong>Tensor并行</strong>范式</h2>
<p>前面都是纵向的对模型进行切割, Tensor并行是横向的对Tenosr以及相应的矩阵运算进行切割.</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211111171554.png">
    <img alt="image-20211111171552983" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211111171554.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211111171554.png" style="display: block; margin: 0 auto;"
      alt="image-20211111171552983"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="mixture-of-experts">Mixture of Experts</h2>
<p>结合弱监督学习器来得到一个强学习器, 采用一个专家门控机制来实现, 用一个门控网络G来学习n个专家的概率分布, 将网络的流量导向对应的专家</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211111171820.png">
    <img alt="image-20211111171819467" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211111171820.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211111171820.png" style="display: block; margin: 0 auto;"
      alt="image-20211111171819467"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="other-memory-saving-designs">Other Memory Saving Designs</h2>
<ul>
<li>CPU offloading: 异步的将一些GPU存不下的放到cpu上, 但以不影响Training Process为基准</li>
<li>Mixed Precision Training: 混合精度训练, 实际上应该就是APEX采用的策略.</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>MIM-V-simMIM</title>
      <link>https://aikenh.cn/posts/mim-v-simmim/</link>
      <pubDate>Tue, 23 Nov 2021 06:38:19 +0000</pubDate>
      <guid>https://aikenh.cn/posts/mim-v-simmim/</guid>
      <description>A Simple Framework for Masked Image Modeling</description>
      <content:encoded><![CDATA[<p>@Author： MSRA Zhenda Xie
@Source：<a href="arxiv.org/abs/2111.09886">Arxiv</a>
， <a href="https://github.com/microsoft/SimMIM" target="_blank" rel="noopener">Code TBP</a>
，<a href="https://mp.weixin.qq.com/s/4YVYM9lPYghtZFhyOGnERw" target="_blank" rel="noopener">Blog_CVer</a>

@Read：AikenHong 2021.11.22</p>
<p>“What I cannot create, I do not understand.” — Richard Feynman</p>
<h2 id="intro--simple-conclusion">Intro &amp; Simple Conclusion</h2>
<h3 id="conclusion">Conclusion</h3>
<p>继MAE和iBoT之后，MSRA也提出了一个图像掩码建模的新框架，SimMIM，该方法简化了最近这些提出的方法，不需要特殊设计，作者也验证了不需要那些特殊设计就已经能让模型展现出优秀的学习能力</p>
<ul>
<li>采用中等大小的掩码块（32），对输入图像进行随机掩码，能使其成为强大的代理任务（pretext task）</li>
<li>直接回归预测原始像素的RGB值的效果并不比复杂设计的Patch分类方法差</li>
<li>Projector Head可以是轻量的Linear Layer，效果并不一定比MLP（多层）的差</li>
</ul>
<h3 id="motivation">Motivation</h3>
<p>通过这种MIM方法可以实现在大量无标注的数据上得到一个表征能力up的通用特征模型，这种方式的backbone可以广泛的应用到图像上的各种子任务中（按照NLP）的经验来说，而为了类似的方式在图像上的大放异彩，我们首先需要分析Vision和Language的不同</p>
<ol>
<li><strong>图像有更强的局部关系</strong>：相互靠近的像素是高度相关和近似的，我们可以通过简单的copy padding复制一部分缺失</li>
<li><strong>视觉信号是原始，低层次的，而文本分词是高级概念</strong>：对低层次信号的预测是否对高层次的视觉识别任务有用呢？</li>
<li><strong>视觉信号是连续的，而文本的分词是离散的</strong>： 如何基于分类的掩码语言建模方法来处理连续的视觉信号</li>
</ol>
<h2 id="theoretical-design">Theoretical Design</h2>
<p><strong>掩码选择</strong>：同样的掩码的策略还是基于Patch进行的，对于掩码的设计来说，太大的掩码快或者太密集的掩码快，可能会导致找不到附近的像素来预测，实验证明32是一个具有竞争力的size，和文本任务的信息冗余程度不同也带来了覆盖比的选择，NLP通常是0.15，而在V中，32size可以支持0.1-0.7的覆盖率。</p>
<p><strong>任务选择</strong>：使用原始像素的回归任务，因为回归任务和具有有序性的视觉信号的连续性很好的吻合。</p>
<p><strong>预测头选择</strong>：使用轻量的预测头如（linear），迁移性能与繁琐的预测头相似或者略好，同时训练上更加的块。虽<strong>然较大的头或更高的分辨率通常会导致更强的生成能力，但这种更强的能力不一定有利于下游的微调任务</strong>。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211123104311">
    <img alt="图片" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211123104311"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211123104311" style="display: block; margin: 0 auto;"
      alt="图片"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="structure-design">Structure Design</h2>
<p><code>SimMIM</code>方法就是掩码表示学习，实际上就是掩码图像然后预测原始信号，主要的组成部分、</p>
<ol>
<li>Masking Strategy，选择图像掩码掩码区域，并实现掩码，将掩码后的图像作为图像的模型输入</li>
<li>Encoder Architecture， 提取特征表示，用来预测原始信号，主要采用<code>vanilla VIT</code>和<code>Swin Transformer</code></li>
<li>Prediction Head，用于预测潜在的特征表示，表示掩码区域中的原始信号</li>
<li>Prediction target，定义了要预测的原始信号的形式，可以是原始像素值也有可以是元素像素变换。同时定义了损失：分类<code>ce</code>，回归<code>l1</code>，<code>l2</code></li>
</ol>
<h3 id="masking">Masking</h3>
<p>使用可学习的mask token vector代替每个掩码区域，这个token向量的维度和其他的可见patch，经过patch embedding后的维数相同，主要测试了以下的几种策略：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211123104416.png">
    <img alt="image-20211123104415318" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211123104416.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211123104416.png" style="display: block; margin: 0 auto;"
      alt="image-20211123104415318"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="projector-head">Projector Head</h3>
<p>形式和大小任意，只要输入和编码器的输入是一致的，其输出达到预期目标即可，只是本文的作者证明了预测头可以做成轻量的单层线性层。</p>
<p>也测试过<code>2layers-MLP</code>，<code>inverse Swin-T/B</code></p>
<h3 id="projector-targets">Projector Targets</h3>
<p>原始像素之回归，一般情况下视觉框架生成下采样分辨率的特征图，ViT为<code>16*</code>其他架构为<code>32*</code></p>
<p>为了预测输入图像全分辨率下的所有像素值，</p>
<ol>
<li>
<p>将feature map中的每个特征向量映射回原始分辨率，并让该向量负责相应的原始像素的预测</p>
<blockquote>
<p>例如，对于Swin Transformer编码器生成的32×下采样的feature map，作者使用输出维数为3072 = 32×32×3的1×1卷积(线性)层来表示32×32像素的RGB值。对原始图像分别进行{32×， 16×， 8×， 4×， 2×}下采样，考虑分辨率较低的目标。</p>
</blockquote>
</li>
<li>
<p>在掩码像素上使用L1-Loss，

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211123105005.png">
    <img alt="image-20211123104929407" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211123105005.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211123105005.png" style="display: block; margin: 0 auto;"
      alt="image-20211123104929407"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
</li>
<li>
<p>可以使用其他的预测目标：</p>
<ul>
<li><strong>Color clustering</strong>. 在iGPT中，利用大量自然图像，通过k-means将RGB值分成512个簇。然后每个像素被分配到最近的簇中心。这种方法需要一个额外的聚类步骤来生成9位调色板。在实验中，作者使用了在iGPT中学习到的512簇中心。</li>
<li><strong>Vision tokenization</strong>. 在BEiT中，采用离散VAE (dVAE)网络将图像patch转换为dVAE tokens。token可用作为分类目标。在这种方法中，需要预训练一个额外的dVAE网络。</li>
<li><strong>Channel-wise bin color discretization.</strong> 将R、G、B通道分别进行分类，每个通道离散为相同的bins，例如实验中使用的8和256 bins。在·</li>
</ul>
</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>Transformer</title>
      <link>https://aikenh.cn/posts/transformer/</link>
      <pubDate>Tue, 23 Nov 2021 06:38:19 +0000</pubDate>
      <guid>https://aikenh.cn/posts/transformer/</guid>
      <description>&lt;p&gt;@aikenhong 2021&lt;/p&gt;
&lt;p&gt;References For Transformer:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;NLP &lt;a href=&#34;https://lilianweng.github.io/lil-log/2020/04/07/the-transformer-family.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;The Transformer Family (lilianweng.github.io)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;VIT &lt;a href=&#34;https://mp.weixin.qq.com/s?__biz=MjM5ODExNDA2MA==&amp;amp;mid=2449941486&amp;amp;idx=1&amp;amp;sn=336a47a31f4b4ff0f6cd8e2fc3cb184a&amp;amp;chksm=b13c258d864bac9b32d10ec36a058d77cc7cf90e066e76ae476fd2fde1b54256cd608a559bb6&amp;amp;mpshare=1&amp;amp;scene=23&amp;amp;srcid=1101rcBaNzO4pu00PCPsJOAl&amp;amp;sharer_sharetime=1635744838591&amp;amp;sharer_shareid=ec299f1c891fc72cd699f8eaeb8a0cd5#rd&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Transformer眼中世界 VS CNN眼中世界&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;李沐 NLP &lt;a href=&#34;https://www.bilibili.com/video/BV1pu411o7BE?spm_id_from=333.999.0.0&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Transformer论文精读&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Suveys &lt;a href=&#34;https://mp.weixin.qq.com/s?__biz=MzUxNjcxMjQxNg==&amp;amp;mid=2247514162&amp;amp;idx=2&amp;amp;sn=d094eecbfd91ca1e478c41e29f2b98d5&amp;amp;scene=21#wechat_redirect&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;cver1&lt;/a&gt;
， &lt;a href=&#34;https://mp.weixin.qq.com/s?__biz=MzUxNjcxMjQxNg==&amp;amp;mid=2247514982&amp;amp;idx=2&amp;amp;sn=7e38021234b7ab5455429e4485128efd&amp;amp;chksm=f9a1c9e9ced640ff045d1c4fe9d4e98a785602d980b25df4fa18477dd2b4b829ed4fc3fd028f&amp;amp;scene=21#wechat_redirect&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;cver2&lt;/a&gt;
，&lt;a href=&#34;https://mp.weixin.qq.com/s/_th7rXfZDuSu2xo7gdPp0w&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;cver3&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This blog will divided into several part : lil&amp;rsquo;s blog, the survey for ViT, we using those article to help us understand the transformer.&lt;/p&gt;
&lt;p&gt;综述我们以最新的一篇为准进行阅读，其他的可能后续进行查缺补漏把，如无必要，勿增烦恼。&lt;/p&gt;
&lt;h2 id=&#34;intro导言&#34;&gt;Intro导言&lt;/h2&gt;
&lt;p&gt;主要参考文章2来进行我们简单的导入&lt;/p&gt;
&lt;h3 id=&#34;基本问题&#34;&gt;基本问题&lt;/h3&gt;
&lt;p&gt;Transformer原本是NLP中的重要模型, 作为LSTM的后继者, 用于处理Seq2Seq的数据类型和情景, 若是要将Transformer运用到Vision的领域中, 首要的问题就是如何:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;将Image作为序列化的Token输入Transform中&lt;/strong&gt; , 而达成这个目的主要有三种典型的方法:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;像素点作为token,&lt;/li&gt;
&lt;li&gt;使用VAE离散化图片作为token再输入&lt;/li&gt;
&lt;li&gt;ViT: 将图片切为一个个&lt;code&gt;Patch&lt;/code&gt;在经过线性的&lt;code&gt;projector&lt;/code&gt;之后组成一个&lt;code&gt;embedding&lt;/code&gt;表示进行交互&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;div class=&#34;post-img-view&#34;&gt;
  &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211120010516&#34;&gt;
    &lt;img alt=&#34;图片&#34; loading=&#34;lazy&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211120010516&#34;class=&#34;responsive-image&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211120010516&#34; style=&#34;display: block; margin: 0 auto;&#34;
      alt=&#34;图片&#34;  /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;script&gt;
  document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
      var images = document.querySelectorAll(&#34;.responsive-image&#34;);
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + &#34;px&#34;;
      });
  });
&lt;/script&gt;
&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>@aikenhong 2021</p>
<p>References For Transformer:</p>
<ol>
<li>NLP <a href="https://lilianweng.github.io/lil-log/2020/04/07/the-transformer-family.html" target="_blank" rel="noopener">The Transformer Family (lilianweng.github.io)</a>
</li>
<li>VIT <a href="https://mp.weixin.qq.com/s?__biz=MjM5ODExNDA2MA==&amp;mid=2449941486&amp;idx=1&amp;sn=336a47a31f4b4ff0f6cd8e2fc3cb184a&amp;chksm=b13c258d864bac9b32d10ec36a058d77cc7cf90e066e76ae476fd2fde1b54256cd608a559bb6&amp;mpshare=1&amp;scene=23&amp;srcid=1101rcBaNzO4pu00PCPsJOAl&amp;sharer_sharetime=1635744838591&amp;sharer_shareid=ec299f1c891fc72cd699f8eaeb8a0cd5#rd" target="_blank" rel="noopener">Transformer眼中世界 VS CNN眼中世界</a>
</li>
<li>李沐 NLP <a href="https://www.bilibili.com/video/BV1pu411o7BE?spm_id_from=333.999.0.0" target="_blank" rel="noopener">Transformer论文精读</a>
</li>
<li>Suveys <a href="https://mp.weixin.qq.com/s?__biz=MzUxNjcxMjQxNg==&amp;mid=2247514162&amp;idx=2&amp;sn=d094eecbfd91ca1e478c41e29f2b98d5&amp;scene=21#wechat_redirect" target="_blank" rel="noopener">cver1</a>
， <a href="https://mp.weixin.qq.com/s?__biz=MzUxNjcxMjQxNg==&amp;mid=2247514982&amp;idx=2&amp;sn=7e38021234b7ab5455429e4485128efd&amp;chksm=f9a1c9e9ced640ff045d1c4fe9d4e98a785602d980b25df4fa18477dd2b4b829ed4fc3fd028f&amp;scene=21#wechat_redirect" target="_blank" rel="noopener">cver2</a>
，<a href="https://mp.weixin.qq.com/s/_th7rXfZDuSu2xo7gdPp0w" target="_blank" rel="noopener">cver3</a>
</li>
</ol>
<p>This blog will divided into several part : lil&rsquo;s blog, the survey for ViT, we using those article to help us understand the transformer.</p>
<p>综述我们以最新的一篇为准进行阅读，其他的可能后续进行查缺补漏把，如无必要，勿增烦恼。</p>
<h2 id="intro导言">Intro导言</h2>
<p>主要参考文章2来进行我们简单的导入</p>
<h3 id="基本问题">基本问题</h3>
<p>Transformer原本是NLP中的重要模型, 作为LSTM的后继者, 用于处理Seq2Seq的数据类型和情景, 若是要将Transformer运用到Vision的领域中, 首要的问题就是如何:</p>
<p><strong>将Image作为序列化的Token输入Transform中</strong> , 而达成这个目的主要有三种典型的方法:</p>
<ul>
<li>像素点作为token,</li>
<li>使用VAE离散化图片作为token再输入</li>
<li>ViT: 将图片切为一个个<code>Patch</code>在经过线性的<code>projector</code>之后组成一个<code>embedding</code>表示进行交互</li>
</ul>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211120010516">
    <img alt="图片" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211120010516"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211120010516" style="display: block; margin: 0 auto;"
      alt="图片"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="cnn的异同分析">CNN的异同分析</h3>
<p>差异分析和计算主要靠CKA向量相似度计算来计算模型和表征之间的差异，这里的理论分析暂且不赘述，后续有需求的话可参考论文Similarity of neural network representations revisited或当前文章.</p>
<ol>
<li>
<p>ViT的深浅特征高度相似, 而CNN则是层次化的存在表征区别.</p>
<p>我想这和网络的结构之间有很大的关系, 序列化的结构和层次化的结构之间存在的差别.</p>
</li>
<li>
<p>ViT最后输出使用的是CLS token, 而CNN最终的Global Pooling导致Vi     T的顶层特征是独特的, 与CNN的深浅都不匹配</p>
</li>
<li>
<p>ViT 模型，在底层就已经是局部和全局信息都混在一起了，而上层则基本都是全局信息。和 ResNet 差别在于，因为 CNN 本身特性，底层只利用局部信息。</p>
<p>此外，当用少量数据训练 ViT 的时候，发现底层的头是学习不到局部信息的。</p>
<p>而这也导致了模型性能不是很好，所以视觉模型需要表现好，底层一般都需要学习到局部信息，这也是符合解剖学里面人类视觉神经结构的。</p>
</li>
<li>
<p>最后一层的空间信息的学习和Pooling有关, 导致了ViT中有更多空间信息.</p>
</li>
</ol>
<h2 id="attention-is-all-you-need-李沐">Attention Is All You Need 李沐</h2>
<p>实际上《Attention is All You Need》就是NLP的Transformer的祖宗，这一篇论文已经反反复复的度过很多次了, 所以这一部分主要用来做查缺补漏。</p>
]]></content:encoded>
    </item>
    <item>
      <title>MIM-V-iBOT</title>
      <link>https://aikenh.cn/posts/mim-v-ibot/</link>
      <pubDate>Thu, 18 Nov 2021 06:35:52 +0000</pubDate>
      <guid>https://aikenh.cn/posts/mim-v-ibot/</guid>
      <description>Image Best Pre-Training With Online Tokenizer</description>
      <content:encoded><![CDATA[<p>@Read: AikenHong 2021</p>
<p>@Author: <a href="https://arxiv.org/abs/2111.07832" target="_blank" rel="noopener">https://arxiv.org/abs/2111.07832</a>
</p>
<p>@解读：<a href="https://mp.weixin.qq.com/s/x4yEfg9eqW6x3Ehxm1HkRA" target="_blank" rel="noopener">Machine Heart</a>
</p>
<h2 id="基本思想">基本思想</h2>
<p>基于NLP中的MLM(Masked Language Model)的核心训练目标: 也就是遮住文本的一部分, 然后通过模型去预测和补全, 这一过程是模型学到泛化的特征, 使用这种方法来进行大规模的与训练范式.</p>
<p>在基本的思想上和MAE采用的是一样的设计, 但是本文中坐着认为visual tokenizer的设计才是其中的关键.</p>
<blockquote>
<p>不同于 NLP 中 tokenization 通过离线的词频分析即可将语料编码为含高语义的分词，图像 patch 是连续分布的且存在大量冗余的底层细节信息。而作者认为一个能够提取图像 patch 中高层语义的 tokenizer 可帮助模型避免学习到冗余的这些细节信息。作者认为视觉的 tokenizer 应该具备两个属性：（a）具备完整表征连续图像内容的能力；(b) 像 NLP 中的 tokenizer 一样具备高层语义。</p>
</blockquote>
<p>文中对tokenizer的设计为一个知识蒸馏的过程:</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211118151616.png">
    <img alt="image-20211118151613545" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211118151616.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211118151616.png" style="display: block; margin: 0 auto;"
      alt="image-20211118151613545"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>文中使用这种在线tokenizer同时来监督这样的MIM过程, 也就是两部分协同学习, 能够较好的保证语义的同时并将图像内容转化为连续的特征分布, 具体的, tokenizer和目标网络狗狗想网络结构, 有移动平均来得到实际的tokenizer.</p>
<p>该形式近期在 DINO [3]中以自蒸馏被提出，并被用以针对同一张图片的两个不同视野在 [CLS] 标签上的优化：</p>
<div>
$$ 
L_{CLS} = - P_{\theta^`}^{[CLS]}(v)^T logP_{\theta}^{[CLS]}(\mu)
 $$
</div>
<p>在该损失函数的基础上, MIM同样也是用这种自蒸馏的方式去优化, 其中在线tokenizer的参数为目标网络历史参数的平均.</p>
<div>
$$ 
L_{MIM} = - \sum_{i=1}^Nm_i *P_{\theta^`}^{patch}(\mu_i)^TlogP_{\theta}^{patch}(\hat{\mu}_i)
 $$
</div>
<p>基于上述的这些训练目标，提出了一种自监督预训练框架iBOT， 同时优化两种损失函数。</p>
<blockquote>
<p>其中，在 [CLS] 标签上的自蒸馏保证了在线 tokenizer 学习到高语义特征，并将该语义迁移到 MIM 的优化过程中；而在 patch 标签上的自蒸馏则将在线 tokenizer 表征的 patch 连续分布作为目标监督 masked patch 的复原。该方法在保证模型学习到高语义特征的同时，通过 MIM 显式建模了图片的内部结构。同时，在线 tokenizer 与 MIM 目标可以一起端到端地学习，无需额外的 tokenizer 训练阶段。</p>
</blockquote>
<p><strong>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211118152543.png">
    <img alt="image-20211118152542810" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211118152543.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/3070imgs/20211118152543.png" style="display: block; margin: 0 auto;"
      alt="image-20211118152542810"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</strong></p>
<blockquote>
<p>预训练时采用孪生网络结构，其中在线 tokenizer 可以看作教师分支的一部分。教师、学生两分支包括结构相同的 backbone 网络和 projection 网络。作者广泛验证了 iBOT 方法搭配不同的 Transformers 作为 backbone，如 Vision Transformers（ViT-S/16, ViT-B/16, ViT-L/16）及 Swin Transformers（Swin-T/7, Swin-T/14）。作者发现共享 [CLS] 标签与 patch 标签的 projection 网络能够有效提升模型在下游任务上的迁移性能。作者还采用了随机 MIM 的训练机制，对每张图片而言，以 0.5 的概率不进行 mask，以 0.5 的概率从 [0.1, 0.5] 区间随机选取一个比例进行 mask。实验表明随机 MIM 的机制对于使用了 multi-crop 数据增强的 iBOT 非常关键。</p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>MIM-V-MAE</title>
      <link>https://aikenh.cn/posts/mim-v-mae/</link>
      <pubDate>Mon, 15 Nov 2021 12:25:45 +0000</pubDate>
      <guid>https://aikenh.cn/posts/mim-v-mae/</guid>
      <description>Masked Autoencoders Are Scalable Vision Learners</description>
      <content:encoded><![CDATA[<p>@Author：Facebook AI Research-Kaiming He
<a href="https://zhuanlan.zhihu.com/p/432663453" target="_blank" rel="noopener">Kaiming-MAE</a>
</p>
<h2 id="conclusion">Conclusion</h2>
<p>总而言之这是一种大模型的训练方法, 通过在少量数据的基础上实现大模型的训练.</p>
<p>整体的架构上是参考了NLP中的AutoEncoder机制，将原图切分patch，用mask掩盖原图，通过少量可见的Patch进行Encoder后和Mask融合，再通过<strong>非对称</strong>的Decoder进行pixel的还原。</p>
<p>这种设计的有点在于mask的scala是可变的，同时这种mask能减少我们训练过程中对显存和计算复杂度的损耗，同时问题本身是一个比较复杂的问题，得以训练复杂的大模型，这种方式最终呈现的效果就是训练的效率高且效益好。</p>
<p>体现了自监督学习在这方面的优越性，同时这种方法得以实现也是由于ViT模型对于CNN模型的取代，才使得这种序列化切块的方式容易实现和验证。</p>
<p>这种方式在最终体现了自监督学习对于有监督与训练的优越性，使用这种方式能够更好的得到一个模型的通用表征。</p>
<p>在这里论文中也说明了和NLP的不同点以及这样的模型对于decoder的要求实际上是比NLP更高的</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211115113546.png">
    <img alt="image-20211115113542074" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211115113546.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211115113546.png" style="display: block; margin: 0 auto;"
      alt="image-20211115113542074"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="experiment">experiment</h2>
<p><strong>Masking</strong>：对于输入的图像进行均匀的切分并均匀的随机采样</p>
<p><strong>MAE encoder</strong>: 简单的ViT模型，对输入图像进行编码后和Mask进行混合得到一个完整的令牌集合，从而确保Decode能够得到对应的位置信息。</p>
<p><strong>MAE decoder</strong>：轻量级的架构，可以独立于编码器进行设计，我们使用更窄更浅的网络，计算量比编码器10%更小，这样能够更快的进行训练。解码器的最后一层是先行投影，输出的数量==补丁中像素值的数量，最后会resize层原图的维度。</p>
]]></content:encoded>
    </item>
    <item>
      <title>OWL-survey</title>
      <link>https://aikenh.cn/posts/owl-survey/</link>
      <pubDate>Fri, 12 Nov 2021 09:40:46 +0000</pubDate>
      <guid>https://aikenh.cn/posts/owl-survey/</guid>
      <description>&lt;p&gt;@AikenHong2021 OWL&lt;/p&gt;
&lt;p&gt;分析现有的OWL特点，和当前自己的研究做一个区分，也汲取一下别人的研究的要点，&lt;/p&gt;
&lt;h2 id=&#34;reference&#34;&gt;Reference&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;arxiv @ &lt;a href=&#34;https://arxiv.org/pdf/2102.07848.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;self-supervised feature improve open-world learning&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://zhuanlan.zhihu.com/p/374268236&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;arxiv&lt;/a&gt;
 @ &lt;a href=&#34;https://arxiv.org/pdf/2102.03526.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;open-world semi-supervised learning&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;arxiv @ &lt;a href=&#34;https://arxiv.org/pdf/2011.12906.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;open-world learning without labels&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;arxiv @ &lt;a href=&#34;https://arxiv.org/pdf/1801.05609.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;unseen class discovery in open-world classification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;arxiv @ &lt;a href=&#34;https://arxiv.org/pdf/2109.06628.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Open-World Active Learning with Stacking Ensemble for Self-Driving Cars&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://dl.acm.org/doi/pdf/10.1145/3308558.3313644&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;www&lt;/a&gt;
 @ &lt;a href=&#34;https://blog.csdn.net/u011150266/article/details/118242627&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;open-world learning and application to product classification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;cvpr @ &lt;a href=&#34;https://openaccess.thecvf.com/content/CVPR2021/papers/Mancini_Open_World_Compositional_Zero-Shot_Learning_CVPR_2021_paper.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;open world composition zero-shot learning&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://arxiv.org/pdf/2103.02603.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;cvpr&lt;/a&gt;
 @ &lt;a href=&#34;https://zhuanlan.zhihu.com/p/356272271&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Towards Open World Object Detection&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[cvpr](&lt;a href=&#34;https://openaccess.thecvf.com/content_CVPR_2019/papers/Liu_Large-Scale_Long-Tailed_Recognition_in_an_Open_World_CVPR_2019_paper.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Large-Scale Long-Tailed Recognition in an Open World (thecvf.com)&lt;/a&gt;
) @ &lt;a href=&#34;https://github.com/zhmiao/OpenLongTailRecognition-OLTR&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Large-Scale Long-Tailed Recognition in an Open World&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;h2 id=&#34;papers&#34;&gt;Papers&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Mulit Open world Learning Definition&lt;/strong&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>@AikenHong2021 OWL</p>
<p>分析现有的OWL特点，和当前自己的研究做一个区分，也汲取一下别人的研究的要点，</p>
<h2 id="reference">Reference</h2>
<ol>
<li>arxiv @ <a href="https://arxiv.org/pdf/2102.07848.pdf" target="_blank" rel="noopener">self-supervised feature improve open-world learning</a>
</li>
<li><a href="https://zhuanlan.zhihu.com/p/374268236" target="_blank" rel="noopener">arxiv</a>
 @ <a href="https://arxiv.org/pdf/2102.03526.pdf" target="_blank" rel="noopener">open-world semi-supervised learning</a>
</li>
<li>arxiv @ <a href="https://arxiv.org/pdf/2011.12906.pdf" target="_blank" rel="noopener">open-world learning without labels</a>
</li>
<li>arxiv @ <a href="https://arxiv.org/pdf/1801.05609.pdf" target="_blank" rel="noopener">unseen class discovery in open-world classification</a>
</li>
<li>arxiv @ <a href="https://arxiv.org/pdf/2109.06628.pdf" target="_blank" rel="noopener">Open-World Active Learning with Stacking Ensemble for Self-Driving Cars</a>
</li>
<li><a href="https://dl.acm.org/doi/pdf/10.1145/3308558.3313644" target="_blank" rel="noopener">www</a>
 @ <a href="https://blog.csdn.net/u011150266/article/details/118242627" target="_blank" rel="noopener">open-world learning and application to product classification</a>
</li>
<li>cvpr @ <a href="https://openaccess.thecvf.com/content/CVPR2021/papers/Mancini_Open_World_Compositional_Zero-Shot_Learning_CVPR_2021_paper.pdf" target="_blank" rel="noopener">open world composition zero-shot learning</a>
</li>
<li><a href="https://arxiv.org/pdf/2103.02603.pdf" target="_blank" rel="noopener">cvpr</a>
 @ <a href="https://zhuanlan.zhihu.com/p/356272271" target="_blank" rel="noopener">Towards Open World Object Detection</a>
</li>
<li>[cvpr](<a href="https://openaccess.thecvf.com/content_CVPR_2019/papers/Liu_Large-Scale_Long-Tailed_Recognition_in_an_Open_World_CVPR_2019_paper.pdf" target="_blank" rel="noopener">Large-Scale Long-Tailed Recognition in an Open World (thecvf.com)</a>
) @ <a href="https://github.com/zhmiao/OpenLongTailRecognition-OLTR" target="_blank" rel="noopener">Large-Scale Long-Tailed Recognition in an Open World</a>
</li>
</ol>
<h2 id="conclusion">Conclusion</h2>
<h2 id="papers">Papers</h2>
<p><strong>Mulit Open world Learning Definition</strong></p>
<p>拒绝未见过的类的实例，逐步学习新的类扩展现有模型</p>
<h3 id="zap-large-scale-long-tailed-recognition-in-an-open-world">:zap: Large-Scale Long-Tailed Recognition in an Open World</h3>
<p><a href="https://liuziwei7.github.io/projects/LongTail.html" target="_blank" rel="noopener">Large-Scale Long-Tailed Recognition in an Open World (liuziwei7.github.io)</a>
</p>
<p><a href="https://blog.csdn.net/pingguolou/article/details/107125251" target="_blank" rel="noopener">Translation</a>
</p>
<p>这篇文章很可能作为后续我们比较的baseline，通过对这篇文章的数据和代码复用和同等环境下的处理，来进行算法优劣的比较。但是实际上该论文的定位和我们也并非完全相同，因为改论文将开放世界的类别识别为未知类，主要的问题是如何避免将未知类别分类到少样本类别中。</p>
<blockquote>
<p>我们希望将开放类作为新类别数据处理（Few-Shot），增加了Incremental的部分，这是他们论文中缺少的一部分，同时这篇论文的思路面向的任务是识别而不是分类，他们在识别上的信息实际上是更完善的，但是对于分类任务来说，如果不基于相应的标签先验，实际上容易带来问题。</p>
</blockquote>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211112170439.png">
    <img alt="image-20211112170435667" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211112170439.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211112170439.png" style="display: block; margin: 0 auto;"
      alt="image-20211112170435667"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>使用<strong>动态元嵌入</strong>的策略来结合两个部分处理尾部识别的鲁棒性：</p>
<ol>
<li>从输入图像计算得到直接特征（这一方面上FS的类别缺乏足够的监督）</li>
<li>视觉记忆相关的诱导特征（来源于基于memory的meta-learning），这种特征（visual-memory）具有直接的判别中心，学习一种方法从直接的特征中学到相关的记忆摘要，通过这种meta-embedding来处理尾部的类别。</li>
</ol>
<blockquote>
<p>我们的测试过程是否也可以看作管理一个Memory，通过对Memory的定时定量的Dynamic-Evaluation来做后续的Incremental Learning，通过这种策略来将整个框架整合起来，从最初的模型到后续的模型增量就能更好的结合在一起。</p>
</blockquote>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211112173844.png">
    <img alt="image-20211112173841831" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211112173844.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20211112173844.png" style="display: block; margin: 0 auto;"
      alt="image-20211112173841831"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>这个方法主要是在进行分类的同时维护一个嵌入图，通过对应的距离关系来计算类别的质心，来做作为另一个角度的特征，然后讲特征整合后作为最终的特征依据</p>
<h3 id="zapopen-world-learning-and-application-to-product-classification">:zap:Open-world Learning and Application to Product Classification</h3>
<p>重点：该模型维护一组动态可见类，允许添加或删除新类，而无需重新训练模型。每个类由以小组训练示例表示，在测试中元分类器仅使用已维护的可见类，进行分类和拒绝。</p>
<p>基于metric进行判别和分类</p>
<p>实际上是一种prototype的方法，通过维护类别原型，使用metric的方法进行是否是已知类别的判断。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210923112144">
    <img alt="img" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210923112144"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210923112144" style="display: block; margin: 0 auto;"
      alt="img"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>Ranker的作用是在每个已知类中抽取与一个测试样例的最近邻的k个已知类样例，然后将这些已知类的k个样例存入Meta-Classifier的Memory中。Meta-Classifier将测试样例与Memory中，经过Matching layer与Aggregation layer输出测试样例属于相应已知类的概率得分。</p>
<p>本文最大的新颖之处在于，在解决开集识别问题时，采用meta-learning的思想，训练集、测试集、验证机中的类别完全不相交。这样做的好处是模型具备增量学习的能力，当源源不断的unknown样例进行测试时，完全不必重新训练模型，提供了open-set classification一种新的模式。</p>
<h3 id="zaptowoo">:zap:TOWOO</h3>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210923105625.png">
    <img alt="image-20210923105620398" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210923105625.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210923105625.png" style="display: block; margin: 0 auto;"
      alt="image-20210923105620398"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>整体思路类似，聚类方法，标记出感兴趣的类别，然后加入数据库</p>
<p>1）将未识别的对象，识别为unknown</p>
<p>2）在<strong>逐步接受相应</strong>的标签的时候逐步学习这些未知类别，而不会忘记旧的类别。</p>
<p>使用contrastive cluster和energe-base的方法来对新类进行分类，主要的方法是通过将不确定的类别识别为未知类别。</p>
<p><strong>未知类别识别方法（energe-base）</strong></p>
<p>&hellip;</p>
<h3 id="open-world-compositional-zero-shot-learning">Open World Compositional Zero-Shot Learning</h3>
<p>假设搜索空间是先验已知的，也就是存在几种类别是已知的，但是我们训练集中是没有未知类别的，共享特征空间，通过类似A-softmax的方式做匹配分析，通过在已知类别中落入的位置来判断是我们认定的已知类别还是未知类别。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210923114539.png">
    <img alt="image-20210923114526762" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210923114539.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210923114539.png" style="display: block; margin: 0 auto;"
      alt="image-20210923114526762"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210923114609.png">
    <img alt="image-20210923114607851" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210923114609.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210923114609.png" style="display: block; margin: 0 auto;"
      alt="image-20210923114607851"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="open-world-semi-supervised-learning">Open World Semi-Supervised Learning</h3>
<p>开放世界半监督学习，使用一种同时分类和聚类数据的方法 ORCA：</p>
<p>为了解决这个问题，本文提出了ORCA，一种学习<strong>同时分类和聚类数据</strong>的方法。ORCA将未标记数据集中的例子分类到以前见过的类中，或者通过将相似的例子组合在一起形成一个新的类。ORCA的关键思想是引入基于不确定性的自适应margin，有效地规避由可见类和新类/簇之间的方差不平衡引起的偏差。本文使用图像分类领域的三个常用数据集（CIFAR-10, CIFAR-100，ImageNet） 进行实验验证，结果表明，ORCA在已知类上的性能优于半监督方法，在新类上也优于新类发现方法。</p>
<p><strong>Method</strong></p>
<p>实际上就是使用半监督SimClr的backbone然后通过设定好的位置类别数目的分类器去做训练，但是这里的<strong>损失</strong>防止对已知类的偏向性。可以参考文章中的损失</p>
<p>基于对比学习方法SimCLR进行与训练</p>
<p>已知类的分类头用于将未标记的例子分配给已知类，而激活附加的分类头允许ORCA发现新类别。我们假设新类的<strong>数量是已知的</strong>，并将其作为算法的输入，这是聚类和新类发现方法的典型假设。如果不知道新类的数量，这在现实环境中是经常发生的情况，可以从数据中估计出来。在这种情况下，如果头的数量太多，那么ORCA将不会分配任何例子给一些头，所以这些头将永远不会激活，因此ORCA将自动修剪类的数量。我们在实验中进一步解决了这个问题。</p>
<p><strong>related</strong></p>
<p>了解决这种开放世界的问题，目前有2种思路：(1) OOD检测：能够识别已知类的数据，并且能够将所有未知类的数据检测出来，标为&quot;unknown&quot;。这种方法很好的保证了系统鲁棒性，但是无法充分利用未知类数据进行业务扩展；(2) novel class discovery(零样本，领域自适应问题): 利用源域标记数据来学习更丰富的语义表示，然后将学到的知识迁移到目标域（包含新类别），对目标域数据进行聚类。这种方法不能准确识别出已知类，只是对目标域做了聚类。</p>
<h3 id="self-supervised-features-improve-open-world-learning">Self-Supervised Features Improve Open World Learning</h3>
<p>特征提取：使用自监督学习来做特征提取器的训练</p>
<p>将新类发现作为特征空间中的位置标签，我们根据检测到的样本属于哪一个空间来做检测</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210923132817.png">
    <img alt="image-20210923132813590" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210923132817.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210923132817.png" style="display: block; margin: 0 auto;"
      alt="image-20210923132813590"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>和我的想法还是蛮贴近的，总之也是把新类的标签放置到存储区中，赋予伪标签的过程，然后微调特征提取器，基于后续的数据添加分类器的权重</p>
<h3 id="unseen-class-discovery-in-open-world-classification">Unseen Class Discovery in Open-World Classification</h3>
<p>通过对已知类别的学习，分析已知类别之间的距离差异；</p>
<p>本文的模型提出了一个contrasive模型，对实例属于同一类还是不同类进行分类，该子模型也可以作为聚类的距离函数.</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210923141407.png">
    <img alt="image-20210923141403629" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210923141407.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210923141407.png" style="display: block; margin: 0 auto;"
      alt="image-20210923141403629"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
]]></content:encoded>
    </item>
    <item>
      <title>Python01 数据模型和常用数据结构</title>
      <link>https://aikenh.cn/posts/python/</link>
      <pubDate>Wed, 27 Oct 2021 14:19:13 +0000</pubDate>
      <guid>https://aikenh.cn/posts/python/</guid>
      <description>my personal notebook for python, record basic knowledge</description>
      <content:encoded><![CDATA[<p>个人的《Python Cookbook》 &amp;&amp; 《Fluent Python》阅读笔记。</p>
<h1 id="数据模型python结构的通用范式">数据模型（Python结构的通用范式）</h1>
<p>（Magic method）dunder method：Python特有的双下划线方法，这些方法能够支持Python进行特殊的调用，实现通用方法在新定义的数据结构上的使用，比如最典型的:</p>
<ul>
<li>
<p><code>__len__()</code>后可以支持<code>len()</code>，获得结构的长度</p>
</li>
<li>
<p><code>__getitem__()</code>后可以支持<code>data[index]</code>来获取相应的元素，切片，等等数组的操作；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 也可以支持类似如下的一些操作</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 从数据结构中随机选出一个items</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">random</span> <span class="kn">import</span> <span class="n">choice</span>
</span></span><span class="line"><span class="cl"><span class="n">choice</span><span class="p">(</span><span class="n">datas</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 也可以支持迭代方法和反迭代方法</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">data</span> <span class="ow">in</span> <span class="n">datas</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="o">...</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">data</span> <span class="ow">in</span> <span class="nb">reversed</span><span class="p">(</span><span class="n">datas</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="o">...</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 也可以支持sort函数</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
</ul>
<p>到这里也就说明了，只要我们在数据结构（class）中定义了相应的dunder method，该class就能支持相应的一系列操作，getitems就可以类比为列表，相应的操作都能够在python解释器下自动的赋予支持。</p>
<p>还有一些好用但不常用的方法：</p>
<ul>
<li><code>__contain__</code>实现的是<code>in</code> ，当没有实现contain的方法的时候会按照顺序在list中进行搜索</li>
<li><code>__abs__</code></li>
<li><code>__repr__</code>实现的是输出的format设置，也就是print的时候的输出形式</li>
<li><code>__eq__</code> 实现的是  == 命令，同时in调用的是__eq__</li>
</ul>
<p>下面附上一张特殊方法表：</p>
<h3 id="基本命名规范">基本命名规范</h3>
<p>相关的文件和函数等命名规则。</p>
<p><a href="Python%20Notebook%20ad3f0aafe5a54942bdcc3694a9a88976/%E5%91%BD%E5%90%8D%E6%A0%B7%E4%BE%8B%E8%A1%A8%2039d2a928f8bf4624afc2e0006ffcd528.csv">命名样例表</a>
</p>
<h1 id="变量赋值传递时的引用和拷贝">变量赋值传递时的引用和拷贝</h1>
<p>Python 变量的传递类型：（赋值过程）
<a href="https://www.runoob.com/w3cnote/python-variable-references-and-copies.html" target="_blank" rel="noopener">https://www.runoob.com/w3cnote/python-variable-references-and-copies.html</a>
</p>
<p>Python 赋值过程中不明确区分拷贝和引用，一般对静态变量的传递为拷贝，对动态变量的传递为引用。（注，对静态变量首次传递时也是引用，当需要修改静态变量时，因为静态变量不能改变，所以需要生成一个新的空间存储数据）。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span></span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code>•  字符串，数值，元组 均为静态变量
• 列表，字典为动态变量。</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以用id（）查看指向的地址</p>
<p>在修改列表值之类的时候要注意这一点，不然可能会影响到源列表，可能要使用深拷贝的方法，
copy.deepcopy()</p>
<p>python 定义方法时候指定<a href="https://www.cnblogs.com/xxpythonxx/p/12198876.html" target="_blank" rel="noopener">参数，返回值和变量的类型</a>
：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">test</span><span class="p">(</span><span class="n">a</span><span class="p">:</span><span class="nb">int</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span><span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="mi">1000</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">test</span><span class="p">(</span><span class="s1">&#39;test&#39;</span><span class="p">,</span> <span class="s1">&#39;abc&#39;</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h1 id="类与函数">类与函数</h1>
<p>args，kwargs的用法和解包，主要将字典作为参数整体传入的这种方法值得学习</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">可以用</span><span class="o">*</span><span class="err">，</span><span class="o">**</span><span class="n">定义和解包</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>id()可以获取变量的地址，type（）查看数据类型，isinstance判断类型</p>
<p>locals().keys() 获得当前已经声明的变量列表</p>
<p>sys.argv[0] 可获取当前工作区的地址</p>
<h2 id="匿名函数">匿名函数</h2>
<h2 id="单下划线">单下划线</h2>
<p>定义的函数，属性，或者方法 这表明这个member是受保护的：</p>
<ul>
<li>是用来指定私有变量和方法的方式（只是一种约定习惯）,不希望被下游的程序员直接访问的函数。</li>
<li>如果使用<code>from a_module import</code>导入时，这部分变量和函数不会被导入</li>
<li>但是如果使用 <code>import a_module</code>这样导入模块，仍然可以用<code>a_module._pythonPoint</code>这样的形式访问到这样的对象。</li>
</ul>
<h2 id="bool-and-or-not">Bool and or not</h2>
<p>基本的就不用daaaaaaaaaaaaaaaaaaa说了，主要是一些特殊的用法举例</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># not 会先于 and 执行</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="ow">not</span> <span class="n">flag1</span> <span class="ow">and</span> <span class="n">flag2</span> <span class="o">==</span> <span class="kc">True</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>用逻辑运算符做参数选择</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">judge</span> <span class="o">=</span> <span class="n">index</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">num1</span> <span class="ow">or</span> <span class="n">num2</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="argparse">Argparse</h2>
<p>基本的用法：参考universal framework即可，主要是bool类型无法通过命令行传入</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 使用store_true属性，就可以执行默认的True or False</span>
</span></span><span class="line"><span class="cl"><span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">&#34;--bool_chose&#34;</span><span class="p">,</span><span class="n">default</span><span class="o">=</span><span class="kc">False</span> <span class="p">,</span><span class="n">action</span><span class="o">=</span><span class="s1">&#39;store_true&#39;</span><span class="p">,</span><span class="n">help</span><span class="o">=</span><span class="s1">&#39;a switch of bool variable&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 👇选择上与原本完全是相反的</span>
</span></span><span class="line"><span class="cl"><span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">&#34;--bool_chose&#34;</span><span class="p">,</span><span class="n">default</span><span class="o">=</span><span class="kc">True</span> <span class="p">,</span><span class="n">action</span><span class="o">=</span><span class="s1">&#39;store_true&#39;</span><span class="p">,</span><span class="n">help</span><span class="o">=</span><span class="s1">&#39;a switch of bool variable&#39;</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="random">Random</h2>
<p>使用<strong>sample</strong>不重复的选取字典或者列表中的指定项</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nb">list</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">choose</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">sample</span><span class="p">(</span><span class="nb">list</span><span class="p">,</span><span class="mi">2</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>使用<strong>choice</strong>进行可重复的选取</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">c_r</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">20</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">c_i</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">c_r</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">c_i</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>打乱列表排序</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">A</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 得到index的列表</span>
</span></span><span class="line"><span class="cl"><span class="n">B</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">A</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 对该列表进行打乱，通过打乱的列表进行索引</span>
</span></span><span class="line"><span class="cl"><span class="n">random</span><span class="o">.</span><span class="n">shuffle</span><span class="p">(</span><span class="n">B</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">B</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h1 id="logging-system">Logging System</h1>
<p><a href="https://docs.python.org/zh-cn/3.9/howto/logging.html#logging-basic-tutorial" target="_blank" rel="noopener">日志 HOWTO — Python 3.9.4 文档</a>
；<a href="https://docs.python.org/zh-cn/3.9/howto/logging-cookbook.html#logging-cookbook" target="_blank" rel="noopener">日志操作手册 — Python 3.9.4 文档</a>
</p>
<p><a href="https://www.cnblogs.com/yyds/p/6901864.html" target="_blank" rel="noopener">Python logging模块</a>
；<a href="https://blog.csdn.net/hunt_ing/article/details/82080923" target="_blank" rel="noopener">logging模块的简单使用</a>
</p>
<h2 id="基础使用">基础使用</h2>
<p>从一个非常简单的例子开始，默认的命令行输出等级是warning</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">logging</span>
</span></span><span class="line"><span class="cl"><span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;this message should only show up in log file&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;so do this one &#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">&#39;this one will also show up in the console&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">logging</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s1">&#39;And non-ASCII stuff, too, like resund and Malm&#39;</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>假如我们设置log文件的存储以及输出的格式（包括算法运行的时间）</p>
<ul>
<li>但是注意这个config是一次性设置，只有第一次设置是有效的</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="nb">format</span><span class="o">=</span><span class="s1">&#39;</span><span class="si">%(asctime)s</span><span class="s1"> </span><span class="si">%(levelname)s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1"> &#39;</span><span class="p">,</span> <span class="n">datefmt</span><span class="o">=</span><span class="s1">&#39;%Y-%m-</span><span class="si">%d</span><span class="s1"> %I:%M:%S %p&#39;</span><span class="p">,</span>   <span class="n">filename</span><span class="o">=</span><span class="s2">&#34;exampleFile.log&#34;</span><span class="p">,</span><span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 这里设置了文件的输出名称和输出的格式，以及相应的记录到文件中的等级</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>也可以从命令行设置日志等级,可以获取当前的等级</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">--log <span class="o">=</span> INFO
</span></span><span class="line"><span class="cl"><span class="c1"># getattr 这个方法目前好像还有点问题，</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="进阶使用">进阶使用</h2>
<p>通过4个module的组合来实现record log的功能，通过Logger载入多个Handler，可以通过不同的标准和方式在多个File以及控制台输出不同Level的东西，这就是主要的功能。</p>
<p><a href="Python%20Notebook%20ad3f0aafe5a54942bdcc3694a9a88976/Untitled%20Database%209ccf70326eeb44a0b8e876f6a26ea12c.csv">Untitled</a>
</p>
<p>具体的实现样例如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">logging</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># create logger to record log messages</span>
</span></span><span class="line"><span class="cl"><span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;textlogger&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 避免等级c</span>
</span></span><span class="line"><span class="cl"><span class="n">logger</span><span class="o">.</span><span class="n">propagate</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl"><span class="n">logger</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># create file handler which logs even debug messages</span>
</span></span><span class="line"><span class="cl"><span class="n">fh</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">FileHandler</span><span class="p">(</span><span class="s1">&#39;exampleFile.log&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">fh</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">WARNING</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># creatr console handler...</span>
</span></span><span class="line"><span class="cl"><span class="n">ch</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">amHandler</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">ch</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># create output format  for all the handler</span>
</span></span><span class="line"><span class="cl"><span class="n">formatter</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">Formatter</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">%(asctime)s</span><span class="s1"> </span><span class="si">%(levelname)s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1"> &#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="n">datefmt</span><span class="o">=</span><span class="s1">&#39;%Y-%m-</span><span class="si">%d</span><span class="s1"> %I:%M:%S %p&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ch</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">formatter</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">fh</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">formatter</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># add handler to logger</span>
</span></span><span class="line"><span class="cl"><span class="n">logger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">ch</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">logger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">fh</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># record logs</span>
</span></span><span class="line"><span class="cl"><span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;this message should only show up in log file </span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s1">&#39;test is&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">&#39;so do this one &#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">&#39;this one will also show up in the console&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s1">&#39;show up twice&#39;</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>但是这种格式的时候怎么实现跨文件传输呢？</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">再同个文件中我们只需要进行getlogger使用同一个名字即可获得同一个logger</span><span class="err">，</span><span class="n">但是跨文件的话可能还是需要传递logger把</span><span class="err">。</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>我认为应该传递该<code>logger</code>,然后通过该Logger进行统一的输出，遇到不同的输出要求的时候，我们可以对handler进行不一样的处理从而能够得到多样化的logger输出</p>
<h2 id="logger与装饰器的组合使用">Logger与装饰器的组合使用</h2>
<p>参见后续的装饰器解读模块</p>
<h1 id="files-system">FIles System</h1>
<h2 id="import-manage">Import manage</h2>
<h3 id="__init__py-文件的作用"><strong>init</strong>.py 文件的作用</h3>
<p><a href="https://www.cnblogs.com/BlueSkyyj/p/9415087.html" target="_blank" rel="noopener"><strong>init</strong>.py 文件使用</a>
</p>
<p>其实主要就是控制着包的导入功能，使用<code>__all__</code>来对应<code>from package import *</code>的功能，我们可以在<code>init</code>中批量的导入我们需要的模块，这样我们就不在需要一个个的进行导入了，基于这种特性，我们也可以编写一个manage fuction，通过config来进行选择性的导入。</p>
<ul>
<li>主要的左右是python中package的标识，不能删除</li>
<li>定义<code>__all__</code>用来进行模糊导入</li>
<li>编写python代码，会在import package的时候同时import，但是推荐在包中创建另外的模块来写，尽量保证该文件简单</li>
</ul>
<h2 id="path-manage">Path Manage</h2>
<h3 id="路径切分">路径切分</h3>
<p>将路径切分成地址和文件：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">os</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span><span class="p">,</span><span class="n">f</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">origin</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;path == &#34;</span><span class="p">,</span><span class="n">p</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;file == &#34;</span><span class="p">,</span><span class="n">f</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>切分出文件的盘符和文件名</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">dev</span><span class="p">,</span><span class="n">left</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">splitdrive</span><span class="p">(</span><span class="n">origin</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>切分出文件和拓展名</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">f</span><span class="p">,</span><span class="n">ext</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">splittext</span><span class="p">(</span><span class="n">origin</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="文件遍历">文件遍历</h2>
<h3 id="oswalk">os.walk()</h3>
<p>简单好用的<strong>目录遍历器</strong>用于在目录树中游走输出目录中的文件名，向上或者向下。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">os</span><span class="o">.</span><span class="n">walk</span><span class="p">(</span><span class="n">top</span><span class="p">,</span><span class="n">topdown</span><span class="p">,</span><span class="n">onerror</span><span class="p">,</span><span class="n">followlinks</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>top：遍历的目录地址</li>
<li>（option）topdown：True的话优先遍历top目录，否则会优先遍历子目录</li>
<li>（option）onerror：当需要异常的时候，会调用</li>
<li>（option）followlinks：是否要跳转到快捷方式（或者软连接遍历）</li>
</ul>
<p><strong>RETURN：（root，dirs，files）</strong></p>
<ol>
<li>root：根目录</li>
<li>dirs：文件夹中所有目录的名字（子文件夹）</li>
<li>files：目录中所有文件的名字</li>
</ol>
<p><strong>层序遍历每次是该层的所有文件和目录的名字</strong></p>
<h3 id="globglob">Glob.glob()</h3>
<p>文件遍历方法</p>
<h2 id="文件读写">文件读写</h2>
<h1 id="data-structural">Data Structural</h1>
<h2 id="位运算">位运算</h2>
<p>位运算判断奇偶一致性</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># T：奇偶性不一致 F：奇偶性一致</span>
</span></span><span class="line"><span class="cl"><span class="o">(</span>a ^ b<span class="o">)</span> <span class="p">&amp;</span> <span class="m">1</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="二进制操作">二进制操作</h2>
<p>与或非就不用多说，主要是介绍一个module bitarray</p>
<h2 id="序列构成的数组">序列构成的数组</h2>
<p>这一部分主要有几个重点：<strong>列表推导式的使用</strong>、<strong>元组特性和使用</strong></p>
<h3 id="列表推导式的使用">列表推导式的使用</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 将字符串变成Unicode码位</span>
</span></span><span class="line"><span class="cl"><span class="n">symbols</span> <span class="o">=</span> <span class="s1">&#39;sdac@#&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">codes</span> <span class="o">=</span> <span class="p">[</span><span class="nb">ord</span><span class="p">(</span><span class="n">symbol</span><span class="p">)</span> <span class="k">for</span> <span class="n">symbol</span> <span class="ow">in</span> <span class="n">symbols</span> <span class="k">if</span> <span class="nb">ord</span><span class="p">(</span><span class="n">symbol</span><span class="p">)</span> <span class="o">&gt;</span><span class="mi">127</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 与map和filter的比较</span>
</span></span><span class="line"><span class="cl"><span class="n">lists</span><span class="p">(</span><span class="nb">filter</span><span class="p">(</span><span class="k">lambda</span> <span class="n">c</span><span class="p">:</span><span class="n">c</span><span class="o">&gt;</span><span class="mi">127</span><span class="p">,</span> <span class="nb">map</span><span class="p">(</span><span class="nb">ord</span><span class="p">,</span><span class="n">symbols</span><span class="p">)))</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>可以看出列表推导式的表达更为简洁易懂，而且实际上运行的效率也不低</p>
<h3 id="使用列表推导式生成笛卡尔积">使用列表推导式生成笛卡尔积</h3>
<p>举例：每个size有不同的颜色</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">colors</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;black&#39;</span><span class="p">,</span><span class="s1">&#39;blue&#39;</span><span class="p">,</span><span class="s1">&#39;red&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">sizes</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;S&#39;</span><span class="p">,</span><span class="s1">&#39;M&#39;</span><span class="p">,</span><span class="s1">&#39;L&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 先按颜色循环再按size循环，内外层循环的关系</span>
</span></span><span class="line"><span class="cl"><span class="n">tshirts</span> <span class="o">=</span> <span class="p">[(</span><span class="n">color</span><span class="p">,</span><span class="n">size</span><span class="p">)</span> <span class="k">for</span> <span class="n">color</span> <span class="ow">in</span> <span class="n">colors</span> <span class="k">for</span> <span class="n">size</span> <span class="ow">in</span> <span class="n">sizes</span><span class="p">]</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="生成器表达式">生成器表达式</h3>
<p>我们可以使用列表推导来初始化元组、数组、或者其他的数据类型，但是生成器表达式符合了迭代器的协议，可以逐个的产出元素，而不是先建立一个完整的列表，能够节省内存</p>
<p><strong>语法上和列表推导差不多，只不过把方括号换成圆括号而已</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nb">tuple</span><span class="p">(</span><span class="nb">ord</span><span class="p">(</span><span class="n">symbol</span><span class="p">)</span> <span class="k">for</span> <span class="n">symbol</span> <span class="ow">in</span> <span class="n">symbols</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">array</span>
</span></span><span class="line"><span class="cl"><span class="n">array</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="s1">&#39;I&#39;</span><span class="p">,</span><span class="nb">ord</span><span class="p">(</span><span class="n">symbol</span><span class="p">)</span> <span class="k">for</span> <span class="n">symbol</span> <span class="ow">in</span> <span class="n">symbols</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>利用生成器表达式来计算笛卡尔积</strong></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 这样可以更好的体现逐个生成的特性？但是实际上列表推导式也可以把？</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 但是总之是由这样的特性的，能够避免额外的内存占用</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">tshirt</span> <span class="ow">in</span> <span class="p">(</span><span class="s1">&#39;</span><span class="si">%s</span><span class="s1"> </span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span><span class="p">(</span><span class="n">c</span><span class="p">,</span><span class="n">s</span><span class="p">)</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">colors</span> <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">sizes</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">tshirt</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="元组不仅是不可变的列表">元组不仅是不可变的列表</h3>
<h2 id="列表的基本操作">列表的基本操作</h2>
<h3 id="列表的条件加和">列表的条件加和</h3>
<p>有不少类似和条件语句相关的操作，列举一些基本实例如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># np.random.randint?</span>
</span></span><span class="line"><span class="cl"><span class="n">A</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">B</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;origin A　is </span><span class="si">{}</span><span class="s1"> </span><span class="se">\n</span><span class="s1"> And B is </span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">A</span><span class="p">,</span><span class="n">B</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># style 1 相当于转换成一个ToF的list，然后对这样的list直接进行sum</span>
</span></span><span class="line"><span class="cl"><span class="n">same</span> <span class="o">=</span> <span class="p">(</span><span class="n">A</span> <span class="o">==</span> <span class="n">B</span><span class="p">)</span><span class="o">.</span><span class="n">sum</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;</span><span class="se">\n</span><span class="s1">the num of same element in same posi is&#39;</span><span class="p">,</span> <span class="n">same</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="s1">&#39;&#39;&#39;列表的+=，也就是简单拼接操作&#39;&#39;&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">]</span><span class="o">+</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">]</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="列表的数乘">列表的数乘</h3>
<p>列表的数乘是对列表的项数进行一个重复性的扩充，但是注意这种重复不能针对那种特殊类型（也就是赋值会直接基于地址的：引用？）
所以这是对于<strong>项数的操作</strong>而不是对列表中数值的直接操作，参考变量赋值的部分</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">value</span> <span class="o">=</span> <span class="mi">5</span>
</span></span><span class="line"><span class="cl"><span class="n">unlist</span> <span class="o">=</span> <span class="p">[</span><span class="n">value</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">outlist</span> <span class="o">=</span> <span class="n">unlist</span> <span class="o">*</span> <span class="mi">5</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;the output is like that : </span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">outlist</span><span class="p">))</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="range函数常用操作">range函数常用操作</h3>
<ul>
<li><a href="https://docs.python.org/zh-cn/3.7/library/stdtypes.html?highlight=range#range" target="_blank" rel="noopener">https://docs.python.org/zh-cn/3.7/library/stdtypes.html?highlight=range#range</a>
</li>
<li>range生成的并不是列表，而是一个range组而已</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">reallist</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">20</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># range的步长设置</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">20</span><span class="p">,</span><span class="mi">5</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">i</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="universal-method">Universal Method</h2>
<h3 id="sort对列表进行排序">Sort（）对列表进行排序</h3>
<p>sort用于对源列表进行排序，如果指定参数，则使用指定的比较函数
参考资料：https://www.runoob.com/python/att-list-sort.html</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 纯数字的情况就按基本方式进行排列</span>
</span></span><span class="line"><span class="cl"><span class="n">list1</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">,</span><span class="mi">23</span><span class="p">,</span><span class="mi">4</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">list1</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">list1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 类似的string就按找字母表进行逐项排序吧，我是这样理解的</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="队列queue--deque">队列queue &amp; deque</h2>
<h2 id="set集合">SET集合</h2>
<p><a href="https://www.runoob.com/python3/python3-set.html" target="_blank" rel="noopener">https://www.runoob.com/python3/python3-set.html</a>
</p>
<p>{}可以定义字典，也可以用于创建集合
但是空的集合只能用set()定义（因为{}定义的是空字典）
基本的method：</p>
<ol>
<li>add、remove、discard（也是移除，但是假如元素不存在的话也不会报错）</li>
<li>len，clear</li>
</ol>
<p>主要是可以利用其中不会重复的元素的特性来进行特殊的操作</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">basker</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;apple&#39;</span><span class="p">,</span> <span class="s1">&#39;organge&#39;</span><span class="p">,</span> <span class="s1">&#39;apple&#39;</span><span class="p">,</span> <span class="s1">&#39;pear&#39;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;basker:&#39;</span><span class="p">,</span> <span class="n">basker</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="s1">&#39;orange&#39;</span> <span class="ow">in</span> <span class="n">basker</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">a</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="s1">&#39;go straight forward&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 可以在集合中做交并等等集合的操作</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="利用set进行去重">利用set进行去重</h3>
<p>如何利用set对unhashable的data structure进行去重，这里采取的方式是使用tuple对数组进行变换；</p>
<p>实际上unhashable的原因在于对象是可变对象：比如np.array，所以我们将其转换为不可变的tuple之后就可以进行hash的计算从而进行去重了。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 二维数组为例</span>
</span></span><span class="line"><span class="cl"><span class="n">array1</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">rand</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">array1_t</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="nb">tuple</span><span class="p">,</span><span class="n">array1</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">resume</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">array1_t</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 进行转换的时候注意不要进行过度的拆分，上述的方法只适用于二维数组的情况，</span>
</span></span><span class="line"><span class="cl"><span class="n">text</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;abcsd&#39;</span><span class="p">,</span><span class="s1">&#39;dsdc&#39;</span><span class="p">,</span><span class="s1">&#39;cdsda&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">text</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 即可，不然可能会将其中的文本全部拆分出来</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 后续补充一下map的其他用法。[func,iterator?]</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="dicthashmap">Dict，Hashmap</h2>
<p>实际上python中的字典就是hashmap的具体实现，是一个无序的结构</p>
<h3 id="判断字典中的key是否存在的方法">判断字典中的key是否存在的方法</h3>
<p><strong>首先如果我们调用的key不存在的话</strong>： <code>keyerror</code></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="s1">&#39;key1&#39;</span> <span class="ow">in</span> <span class="n">dict1</span>
</span></span><span class="line"><span class="cl"><span class="n">false</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>或者使用get方法，能给不存在的key赋予默认的value,在这个时候出现的则是<code>nameerror</code></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="n">d</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;key1&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="n">d</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;key1&#39;</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="o">-</span><span class="mi">1</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="字典中的常用方法">字典中的常用方法</h3>
<p>…</p>
<h3 id="collectionsdefaultdict-指定dict中未定义key的value">collections.defaultdict 指定dict中未定义key的value</h3>
<ul>
<li>通过指定的默认值，在一些使用场景下可以对dict进行简化的定义</li>
<li>同时也能针对一些特殊的情况，比如说未见数据的情况，进行定义</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 指定list类型用于未定义类别的填充</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">defaultdict</span>
</span></span><span class="line"><span class="cl"><span class="n">dict1</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="n">dict2</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="nb">list</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">dict1</span><span class="p">[</span><span class="s1">&#39;a&#39;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="k">except</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;dict1 print key error&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;dict2 is like &#39;</span><span class="p">,</span> <span class="n">dict2</span><span class="p">[</span><span class="s1">&#39;a&#39;</span><span class="p">])</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span></span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code>dict1 print key error
dict2 is like  []</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 用法2，避免keyerror更容易对其进行赋值</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">defaultdict</span>
</span></span><span class="line"><span class="cl"><span class="n">bags</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;apple&#39;</span><span class="p">,</span> <span class="s1">&#39;orange&#39;</span><span class="p">,</span> <span class="s1">&#39;cherry&#39;</span><span class="p">,</span> <span class="s1">&#39;apple&#39;</span><span class="p">,</span><span class="s1">&#39;apple&#39;</span><span class="p">,</span> <span class="s1">&#39;cherry&#39;</span><span class="p">,</span> <span class="s1">&#39;blueberry&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">count</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="nb">int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">fruit</span> <span class="ow">in</span> <span class="n">bags</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">count</span><span class="p">[</span><span class="n">fruit</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;the count output is like </span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">,</span> <span class="n">count</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># print(locals().keys())</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span></span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code>the count output is like
 defaultdict(&lt;class &#39;int&#39;&gt;, {&#39;apple&#39;: 3, &#39;orange&#39;: 1, &#39;cherry&#39;: 2, &#39;blueberry&#39;: 1})</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 用法3：可以自定义函数作为初始化的函数参数</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 基于这样的方法我们可以定义各种各样的默认值</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">defaultdict</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">defaultvalue</span><span class="p">(</span><span class="n">value</span><span class="o">=</span><span class="mi">2</span><span class="p">):</span> <span class="k">return</span> <span class="n">value</span>
</span></span><span class="line"><span class="cl"><span class="n">dict3</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="n">defaultvalue</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">dict3</span><span class="p">[</span><span class="s1">&#39;hello&#39;</span><span class="p">]</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="vars">Vars（）</h2>
<p><strong>vars()</strong> 函数返回对象object的属性和属性值的字典对象。</p>
<h2 id="python中的数字日期时间计算">Python中的数字日期时间计算</h2>
<p>@Aiken 2020</p>
<p>@Source：《Python Cookbook》 Chapter3 数字日期和时间</p>
<p>主要针对Python中的数字数字运算的运算做一个笔记</p>
<h3 id="获取本机时间的几种方法">获取本机时间的几种方法</h3>
<p>主要为了<strong>方便格式化时间</strong>输出，我们需要将机器时间转换成指定的年月日之类的。
分别来自于time 和 datatime，这两种方式的时间复杂度好像实际上并没有太大的差别，姑且用着把暂时。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">time</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_time</span><span class="p">(</span><span class="nb">type</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nb">type</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span> <span class="n">now</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s1">&#39;%m/</span><span class="si">%d</span><span class="s1">:%H:%M&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span><span class="p">:</span> <span class="n">now</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s1">&#39;%m/</span><span class="si">%d</span><span class="s1">:%H:%M&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">now</span>
</span></span><span class="line"><span class="cl"><span class="n">get_time</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="精确数字运算">精确数字运算</h3>
<p>我们知道python中的计算不是绝对精准的， 浮点的精度是有限的，但是当我们需要进行金融领域或者数学领域的一些高精度要求的计算，可以为其牺牲一定的复杂度的时候👉decimal模块</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">decimal</span> <span class="kn">import</span> <span class="n">Decimal</span>
</span></span><span class="line"><span class="cl"><span class="n">a</span> <span class="o">=</span> <span class="n">Decimal</span><span class="p">(</span><span class="s1">&#39;4.2&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">b</span> <span class="o">=</span> <span class="n">Decimal</span><span class="p">(</span><span class="s1">&#39;2.1&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">,</span> <span class="n">a</span><span class="o">+</span><span class="n">b</span><span class="o">==</span><span class="n">Decimal</span><span class="p">(</span><span class="s1">&#39;6.3&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 注意数据的类型实际上也是Decimal</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 能控制计算的每一方面，包括数字位数和四舍五入之类的，需要创建一个本地的上下文</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">decimal</span> <span class="kn">import</span> <span class="n">localcontext</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 精确度控制</span>
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="n">localcontext</span><span class="p">()</span> <span class="k">as</span> <span class="n">ctx</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">ctx</span><span class="o">.</span><span class="n">prec</span> <span class="o">=</span> <span class="mi">3</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="o">/</span><span class="n">b</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>计算方法中的大数吃小数的情况</strong></p>
<p>(运算中的量纲差异超过17位的浮点数精度的情况)使用math.fsum()函数</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">math</span>
</span></span><span class="line"><span class="cl"><span class="n">nums</span> <span class="o">=</span> <span class="p">[</span><span class="mf">1.23e+18</span><span class="err">，</span><span class="mi">1</span><span class="err">，</span><span class="o">-</span><span class="mf">1.23e+18</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="k">assert</span> <span class="nb">sum</span><span class="p">(</span><span class="n">nums</span><span class="p">)</span> <span class="o">!=</span> <span class="n">math</span><span class="o">.</span><span class="n">fsum</span><span class="p">(</span><span class="n">nums</span><span class="p">),</span> <span class="s1">&#39;the correct ans is fsum </span><span class="si">{}</span><span class="s1">, error ans is sum </span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">math</span><span class="o">.</span><span class="n">fsum</span><span class="p">(</span><span class="n">nums</span><span class="p">),</span><span class="nb">sum</span><span class="p">(</span><span class="n">nums</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># we can find it what we meet and waht we want.</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="数字的格式化输出">数字的格式化输出</h3>
<p>控制输出的格式（精确度，对齐，千分位分割符）<code>format</code></p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">x</span> <span class="o">=</span> <span class="mf">1234.56789</span>
</span></span><span class="line"><span class="cl"><span class="n">anslist</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl"><span class="n">value</span> <span class="o">=</span> <span class="nb">format</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="s1">&#39;0.2f&#39;</span><span class="p">)</span>   <span class="c1"># 👈 两位小数</span>
</span></span><span class="line"><span class="cl"><span class="n">anslist</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">value</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><a href="Python%20Notebook%20ad3f0aafe5a54942bdcc3694a9a88976/Untitled%20Database%20400b9d461cf240e18dd2268ce561adf1.csv">Untitled</a>
</p>
<p><strong>进制转换：</strong></p>
<blockquote>
<p>2,8,16 -&gt; bin（） oct（） hex（）  OR format(x, ‘b’) format(x, ‘o’) format(x, ‘h’)</p>
</blockquote>
<p><strong>复数运算</strong></p>
<blockquote>
<p><code>complex(real, imag)``numpy</code>好像能处理复数<code>cmath</code>一些math无法处理的复数运算</p>
</blockquote>
<p><strong>正负无穷于NaN（非数字）</strong></p>
<blockquote>
<p>inf，-inf，nan， 可以使用float(‘inf’)创建验证 <code>math.isinf()</code></p>
</blockquote>
<p><strong>分数运算</strong></p>
<blockquote>
<p>Fractions（5，4）==5/4.numerator 分子 .denominator 分母</p>
</blockquote>
<h1 id="迭代器">迭代器</h1>
<p>主要包括迭代的模块和解包的一些相关操作：</p>
<h3 id="enumerate-itemszip">enumerate 、items、zip</h3>
<ol>
<li>
<p><code>enumerate</code>可以将可迭代对象，除了dict，解压出来，并自带序号（多加入一个维度）。</p>
</li>
<li>
<p>字典的解包主要靠<code>items（）</code></p>
</li>
<li>
<p><code>zip</code>将可迭代对象作为参数，把每一项可迭代对象中取出一个值，组合成一个个元组，，然后返回。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">for</span> <span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">,</span><span class="n">c</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">A</span><span class="p">,</span><span class="n">B</span><span class="p">,</span><span class="n">C</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="o">...</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
</ol>
<h1 id="元编程">元编程</h1>
<h2 id="some-rules">Some Rules</h2>
<ul>
<li>
<p><code>-&gt;</code>in python: 常常出现在python函数定义的函数名后面，为函数添加元数据，描述函数的返回类型，从而方面开发人员使用。</p>
</li>
<li>
<p>拓展：进行函数内的参数定义的时候也可以用冒号指定类型，以及默认值</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="n">isPre</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">):</span> <span class="k">pass</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li></li>
</ul>
<h2 id="装饰器模块">装饰器模块</h2>
<p>装饰器在我个人的理解里面更像是一个嵌套的函数结构，编写装饰器实际上是为了给函数<strong>套壳</strong>，最根本的目的仍然是为了repeat coding，而这样的写法最直接适用的有以下的几种情况：</p>
<ul>
<li>Timing or Logging</li>
<li>当成函数指针进行函数的传递（但是这点上实际上用类传递的方式可能会更常见一点）</li>
</ul>
<h3 id="basic-type">Basic Type</h3>
<p>最基本的编写样例：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">time</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">functional</span> <span class="kn">import</span> <span class="n">wraps</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">timethis</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;&#39;&#39;Decorator that report the execution time.
</span></span></span><span class="line"><span class="cl"><span class="s1">    this Decorator can not accept parameters&#39;&#39;&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># 通过下面这个内置的装饰器来保留func的元信息 __name__ __doc___之类的</span>
</span></span><span class="line"><span class="cl">    <span class="nd">@wraps</span><span class="p">(</span><span class="n">func</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">wrapper</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span><span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># * ** 来保证可以对func传入各种参数</span>
</span></span><span class="line"><span class="cl">        <span class="n">start</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="n">result</span> <span class="o">=</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">end</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="n">func</span><span class="o">.</span><span class="vm">__name__</span><span class="p">,</span> <span class="n">end</span> <span class="o">-</span> <span class="n">start</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">result</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">wrapper</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="接受参数传递">接受参数传递</h3>
<p>但是这个装饰器实际上不满足我们的需求，我们希望装饰器能<strong>接受传入的参数</strong>，这样的话，我们才能更好的进行print或者是使用logging这个模块。</p>
<p>Then we can write it like this :</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 实际上直观的理解的话，就是在外面再多嵌套一层函数，通过这个函数来对我们的decorator传递需要的参数</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">functional</span> <span class="kn">import</span> <span class="n">wraps</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">logging</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 实现对装饰器的参数传递，同时和</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">logged</span><span class="p">(</span><span class="n">level</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span><span class="n">message</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;&#39;&#39;通过最外层接受参数并将其传递到内层的装饰器中&#39;&#39;&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">decorate</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># setting paramter we passing here</span>
</span></span><span class="line"><span class="cl">        <span class="n">logname</span> <span class="o">=</span> <span class="n">name</span> <span class="k">if</span> <span class="n">name</span> <span class="k">else</span> <span class="n">func</span><span class="o">.</span><span class="n">__moudule__</span>
</span></span><span class="line"><span class="cl">        <span class="n">log</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="n">logname</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">logmsg</span> <span class="o">=</span> <span class="n">message</span> <span class="k">if</span> <span class="n">message</span> <span class="k">else</span> <span class="n">func</span><span class="o">.</span><span class="vm">__name__</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="nd">@wraps</span><span class="p">(</span><span class="n">func</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">def</span> <span class="nf">wrapper</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span><span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">log</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="n">level</span><span class="p">,</span><span class="n">logmsg</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">wrapper</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">decorate</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 但是实际上我们要传递的就是一些输出结果，所以我们不需要用到这一点，只要再内部赋予logging就行了，所以这里我们设定的就是基本的level和logger_nanme</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="修改装饰器参数">修改装饰器参数</h3>
<p>对上面这个装饰器模块进行简单的改进，<strong>就能使得用包装器包装的函数，能够调用附加函数来修改装饰器的参数</strong></p>
<p>（相当于赋予被装饰方法一个对装饰器的类外访问函数）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 这里有个模块就比较猎奇了，以前倒是没见过</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">functional</span> <span class="kn">import</span> <span class="n">wraps</span><span class="p">,</span><span class="n">partial</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">logging</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># utility decorator to attach a functional as an attribute of obj</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">attach_wrapper</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">func</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">func</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">partial</span><span class="p">(</span><span class="n">attach_wrapper</span><span class="p">,</span> <span class="n">obj</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nb">setattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">func</span><span class="o">.</span><span class="vm">__name__</span><span class="p">,</span><span class="n">func</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">func</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#原有装饰器上面添加东西即可</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">logged</span><span class="p">(</span><span class="n">level</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span><span class="n">message</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;&#39;&#39;通过最外层接受参数并将其传递到内层的装饰器中&#39;&#39;&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">decorate</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># setting paramter we passing here</span>
</span></span><span class="line"><span class="cl">        <span class="n">logname</span> <span class="o">=</span> <span class="n">name</span> <span class="k">if</span> <span class="n">name</span> <span class="k">else</span> <span class="n">func</span><span class="o">.</span><span class="n">__moudule__</span>
</span></span><span class="line"><span class="cl">        <span class="n">log</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="n">logname</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">logmsg</span> <span class="o">=</span> <span class="n">message</span> <span class="k">if</span> <span class="n">message</span> <span class="k">else</span> <span class="n">func</span><span class="o">.</span><span class="vm">__name__</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="nd">@wraps</span><span class="p">(</span><span class="n">func</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">def</span> <span class="nf">wrapper</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span><span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">log</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="n">level</span><span class="p">,</span><span class="n">logmsg</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;&#39;&#39;使用nonlocal添加属性修改的模块&#39;&#39;&#39;</span>
</span></span><span class="line"><span class="cl">        <span class="nd">@attach_wrapper</span><span class="p">(</span><span class="n">wrapper</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">def</span> <span class="nf">set_level</span><span class="p">(</span><span class="n">newlevel</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="k">nonlocal</span> <span class="n">level</span>
</span></span><span class="line"><span class="cl">            <span class="n">level</span> <span class="o">=</span> <span class="n">newlevel</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="nd">@attach_wrapper</span><span class="p">(</span><span class="n">wrapper</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">def</span> <span class="nf">set_message</span><span class="p">(</span><span class="n">newmsg</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="k">nonlocal</span> <span class="n">logmsg</span>
</span></span><span class="line"><span class="cl">            <span class="n">logmsg</span> <span class="o">=</span> <span class="n">newmsg</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">wrapper</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">decorate</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@logged</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@logged</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">CRITICAL</span><span class="p">,</span><span class="s1">&#39;example&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">spam</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Spam&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 使用范例:可以再类外调用内内的属性设置了</span>
</span></span><span class="line"><span class="cl"><span class="n">add</span><span class="o">.</span><span class="n">set_message</span><span class="p">(</span><span class="s1">&#39;add called&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">add</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">add</span><span class="o">.</span><span class="n">set_level</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">WARNING</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">add</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="带可选参数的修饰器">带可选参数的修饰器</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 感觉没太理解这个文章中说到的不带参数的意思，难道可以不传入函数吗</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 先把模板放在这</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">logged</span><span class="p">(</span><span class="n">func</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">,</span><span class="n">name</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">message</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">func</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">partial</span><span class="p">(</span><span class="n">logged</span><span class="p">,</span><span class="n">level</span><span class="o">=</span><span class="n">level</span><span class="p">,</span><span class="n">name</span><span class="o">=</span><span class="n">name</span><span class="p">,</span><span class="n">message</span><span class="o">=</span><span class="n">message</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">logname</span> <span class="o">=</span> <span class="n">name</span> <span class="k">if</span> <span class="n">name</span> <span class="k">else</span> <span class="n">func</span><span class="o">.</span><span class="n">__moudule__</span>
</span></span><span class="line"><span class="cl">    <span class="n">log</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="n">logname</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">logmsg</span> <span class="o">=</span> <span class="n">message</span> <span class="k">if</span> <span class="n">message</span> <span class="k">else</span> <span class="n">func</span><span class="o">.</span><span class="vm">__name__</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nd">@wraps</span><span class="p">(</span><span class="n">func</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">wrapper</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span><span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">log</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="n">level</span><span class="p">,</span><span class="n">logmsg</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">wrapper</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="property的用法">@property的用法</h3>
<p>将类别方法转换为类别属性，可以直接用.获取属性值或者对属性进行赋值。</p>
<p><strong>具体的实现和要求在后面再看看</strong></p>
<h1 id="exception">Exception</h1>
<p>@Aiken 2020</p>
<p>Python的异常处理操作：主要内容包括捕捉异常，抛出异常，基于异常进行判断处理等。
基本原理:</p>
<p>参考资料：  <a href="https://www.runoob.com/python3/python3-errors-execptions.html" target="_blank" rel="noopener">python3_错误和异常</a>
 、 <a href="https://www.runoob.com/python/python-exceptions.html" target="_blank" rel="noopener">python3_错误和异常2</a>
</p>
<h2 id="python3-错误和异常">Python3 错误和异常</h2>
<p>**错误：**一般语法解析器的解析错误，换句话说也就是基本的语法错误。
**异常：**语法正确，但是运行期间出现的错误，</p>
<p>异常有很多种类：未定义，类型异常，除数0异常，etc.
&hellip;在附录附加常用常见的错误类型</p>
<h2 id="异常捕捉try-except">异常捕捉try except</h2>
<p>通过try exception 捕捉可能会出现的异常，然后用except，指定当该异常出现时候要执行的命令，可以指定多种异常。</p>
<p>基本的算法流程是：</p>
<ul>
<li>首先，执行 try 子句（在关键字 try 和关键字 except 之间的语句）。</li>
<li>如果没有异常发生，忽略 except 子句，try 子句执行后结束。</li>
<li>如果在执行 try 子句的过程中发生了异常，那么 try 子句余下的部分将被忽略。如果异常的类型和 except 之后的名称相符，那么对应的 except 子句将被执行。</li>
</ul>
<p>如果一个异常没有与任何的 except 匹配，那么这个异常将会传递给上层的 try 中。
完整的算法逻辑如图所示👇，通常可以指使用t-e部分即可</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/try_except_else_finally.png">
    <img alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/try_except_else_finally.png" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/try_except_else_finally.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/try_except_else_finally.png" style="display: block; margin: 0 auto;"
      alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/try_except_else_finally.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>Image1</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1">#主要依赖模块</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">time</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">sys</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>写法的优点</strong></p>
<ul>
<li>在可预见的Exception出现的时候不会中断程序的进行， 可以以指定的方式进行规避，或者针对该情况进行特定的异常处理。</li>
</ul>
<p><strong>else的优势</strong></p>
<ul>
<li>如果try中出现了多个异常，我们可能会忽视其中的一些异常。</li>
<li>可以针对性的进行异常算法设计，这样会使得可读性和便于分析。</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 用try except的方式最好的一点在于，他不会终端程序的执行。</span>
</span></span><span class="line"><span class="cl"><span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">x</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="nb">input</span><span class="p">(</span><span class="s2">&#34;please type in NUMBER &#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;your input is not NUMBER&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># if we donot use t-e</span>
</span></span><span class="line"><span class="cl"><span class="n">x</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="nb">input</span><span class="p">(</span><span class="s2">&#34;repeat you input&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 通过对比，我们可以知道这样执行的好处，在一些无关紧要的地方，</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 可以让程序继续运行而不必因为这些而中断。</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="exception的多种写法和多异常分支">exception的多种写法和多异常分支</h3>
<p>try中的语句可能有<strong>多种异常抛出</strong>的情况：</p>
<ol>
<li>针对不同的异常进行处理。</li>
<li>统一处理不同异常。</li>
<li>统一处理所有类型</li>
</ol>
<p>以上面的代码为例：</p>
<ol>
<li>try except except &hellip;</li>
<li>EXCEPT (TUPLE)</li>
<li>except不带任何参数</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># type 1</span>
</span></span><span class="line"><span class="cl"><span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">x</span> <span class="o">=</span> <span class="mi">123</span>
</span></span><span class="line"><span class="cl"><span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">t</span> <span class="o">=</span> <span class="mi">123</span>
</span></span><span class="line"><span class="cl"><span class="k">except</span> <span class="ne">TypeError</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">y</span> <span class="o">=</span> <span class="mi">123</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># type 2</span>
</span></span><span class="line"><span class="cl"><span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">x</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="nb">input</span><span class="p">(</span><span class="s2">&#34;please type in NUMBER &#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="k">except</span> <span class="p">(</span><span class="ne">ValueError</span><span class="p">,</span><span class="ne">TypeError</span><span class="p">,</span><span class="ne">NameError</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;your input is not NUMBER&#39;</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>Try Import</strong> 使用try的结构来避免import过程中出现的问题：</p>
<p><a href="https://www.programcreek.com/python/?CodeExample=try&#43;import" target="_blank" rel="noopener">Python try import (programcreek.com)</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">try_import</span><span class="p">(</span><span class="n">package</span><span class="p">,</span> <span class="n">message</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nb">__import__</span><span class="p">(</span><span class="n">package</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">ImportError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="ow">not</span> <span class="n">message</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">raise</span> <span class="n">e</span>
</span></span><span class="line"><span class="cl">        <span class="k">raise</span> <span class="ne">ImportError</span><span class="p">(</span><span class="n">m</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="抛出异常-raise-exception">抛出异常 Raise Exception</h2>
<p>使用raise 语句能够抛出指定类型的异常，从而终止程序的运行，和assert断言起到相似的作用。</p>
<p>**关键用法：**设置异常抛出，然后用try except捕捉，然后进行指定的分支操作。
<code>raise [Exception [, args [, traceback]]]</code></p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/raise.png">
    <img alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/raise.png" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/raise.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/raise.png" style="display: block; margin: 0 auto;"
      alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/raise.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>raise_exception</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">x</span> <span class="o">=</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="n">x</span> <span class="o">&gt;=</span> <span class="mi">5</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span><span class="s1">&#39;x 不能大于5，当前值为 </span><span class="si">{}</span><span class="s1"> &#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">x</span><span class="p">))</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h1 id="numpy-tips">Numpy Tips</h1>
<h2 id="reshape">reshape</h2>
<p>和numpy格式的reshape的相关内容整合</p>
<ol>
<li>基本reshape的使用</li>
<li>reshape不改变原数据</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">bk1_a</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">,</span><span class="mi">7</span><span class="p">,</span><span class="mi">8</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="n">bk1_b</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([[</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">],[</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">]])</span>
</span></span><span class="line"><span class="cl"><span class="n">bk1_c</span> <span class="o">=</span> <span class="n">bk1_a</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="n">bk1_b</span><span class="o">.</span><span class="n">shape</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;b&#39;s datashpe is </span><span class="si">{}</span><span class="s2">&#34;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">bk1_b</span><span class="o">.</span><span class="n">shape</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;reshape by b。shape is ↓ </span><span class="se">\n</span><span class="s2"> </span><span class="si">{}</span><span class="s2">&#34;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">bk1_c</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 测试是否改变原数据</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;b&#39;s shape is </span><span class="si">{}</span><span class="s2"> &#34;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">bk1_b</span><span class="o">.</span><span class="n">shape</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="k">assert</span> <span class="n">bk1_a</span> <span class="o">==</span>  <span class="n">bk1_c</span><span class="p">,</span> <span class="s1">&#39;do not change the origin data, a is like </span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">bk1_a</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="tolist">tolist</h2>
<p>numpy array 和list之间的互相转换，在大规模编程中有比较广泛的应用场景。</p>
<ul>
<li>**有^次方的意思</li>
<li>arange 包含下限，不包含上线</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">bk2_a</span><span class="o">=</span> <span class="p">(</span><span class="mi">2</span> <span class="o">**</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span><span class="mi">6</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># bk2_a</span>
</span></span><span class="line"><span class="cl"><span class="n">bk2_b</span> <span class="o">=</span> <span class="n">bk2_a</span><span class="o">.</span><span class="n">tolist</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1"># bk2_b</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="用array给list中的元素赋值">用array给list中的元素赋值</h2>
<p>以下是这种方式建立一个类似one-hot的函数介绍
可以很容易的从输出看出规律，而且最外层仍然是列表，也就是其中的元素是array</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">list1</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">12</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">list1</span><span class="p">)):</span>
</span></span><span class="line"><span class="cl">    <span class="n">temp</span> <span class="o">=</span> <span class="n">list1</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">-</span><span class="mi">1</span>
</span></span><span class="line"><span class="cl">    <span class="n">list1</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">zeros</span><span class="p">(</span><span class="mi">13</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">list1</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">temp</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="n">list1</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="flatten--flat-operation">flatten &amp; flat operation</h2>
<p>flatten：将数据摊开降维成一维的数组/矩阵，以副本形式生成，不影响原数据
flat，生成一个迭代器，按行的形式迭代</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># A:flatten function B:flat function</span>
</span></span><span class="line"><span class="cl"><span class="n">bk3_a</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">rand</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;A is just like</span><span class="se">\n</span><span class="s1"> </span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">bk3_a</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">bk3_a2</span> <span class="o">=</span> <span class="n">bk3_a</span><span class="o">.</span><span class="n">flatten</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;A2 is just like</span><span class="se">\n</span><span class="s1"> </span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">bk3_a2</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">printz</span><span class="p">(</span><span class="s1">&#39;********************clip*************************&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">bk3_b</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">rand</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;B is just like </span><span class="se">\n</span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">bk3_b</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">bk3_b</span><span class="o">.</span><span class="n">flat</span><span class="p">,</span> <span class="s1">&#39;as we can see, this is a iter&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">bk3_b</span><span class="o">.</span><span class="n">flat</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">i</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="numpypad">Numpy.pad</h2>
<p>pad，就是拓展原本数据的维度，方便后面机器学习中的其他步骤，主要用处包括：</p>
<ol>
<li>维度保持</li>
<li>增加对图像边界的重视</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1">## numpy.pad</span>
</span></span><span class="line"><span class="cl"><span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">5</span><span class="p">,(</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">4</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">pad</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">x</span><span class="o">.</span><span class="n">shape</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">h</span><span class="p">,</span><span class="n">w</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span>
</span></span><span class="line"><span class="cl"><span class="n">new_h</span><span class="p">,</span><span class="n">new_w</span> <span class="o">=</span> <span class="mi">3</span><span class="p">,</span><span class="mi">3</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">top</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="n">h</span><span class="o">-</span><span class="n">new_h</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">left</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="n">w</span><span class="o">-</span><span class="n">new_w</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">x</span> <span class="o">=</span> <span class="n">x</span><span class="p">[:,</span><span class="n">top</span><span class="p">:</span> <span class="n">top</span><span class="o">+</span><span class="n">new_h</span><span class="p">,</span><span class="n">left</span><span class="p">:</span><span class="n">left</span><span class="o">+</span><span class="n">new_w</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">x</span><span class="o">.</span><span class="n">shape</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="-numpy-索引中双冒号的实际用途">:: Numpy 索引中双冒号的实际用途</h2>
<p>参照该文章进行分析，主要用途包括：对图像进行反转等操作
<a href="https://blog.csdn.net/GracePro/article/details/102079331" target="_blank" rel="noopener">https://blog.csdn.net/GracePro/article/details/102079331</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">a</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">rand</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;----------------------------&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">a</span> <span class="o">=</span> <span class="n">a</span><span class="p">[:,::</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="argpartition">Argpartition()</h2>
<p>借助于 argpartition()，Numpy 可以找出 N 个最大数值的索引，也会将找到的这些索引输出。<br>然后我们根据需要对数值进行排序。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mi">12</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">12</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">16</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="n">index_val</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">argpartition</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="o">-</span><span class="mi">5</span><span class="p">)[</span><span class="o">-</span><span class="mi">5</span><span class="p">:]</span>
</span></span><span class="line"><span class="cl"><span class="n">index2</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">argmin</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">index2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">index_val</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>基于numpy的sort函数，输出找出的最大的几个数，要全体排序的话，还是考sort</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">np</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="n">index_val</span><span class="p">])</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="allclose">Allclose()</h2>
<p>allclose() 用于匹配两个数组，并得到布尔值表示的输出。如果在一个公差范围内（within a tolerance）两个数组不等同，<br>
则 allclose() 返回 False。该函数对于检查两个数组是否相似非常有用。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">array1</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mf">0.12</span><span class="p">,</span><span class="mf">0.17</span><span class="p">,</span><span class="mf">0.24</span><span class="p">,</span><span class="mf">0.29</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="n">array2</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mf">0.13</span><span class="p">,</span><span class="mf">0.19</span><span class="p">,</span><span class="mf">0.26</span><span class="p">,</span><span class="mf">0.31</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="c1"># with a tolerance of 0.1, it should return False:</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">allclose</span><span class="p">(</span><span class="n">array1</span><span class="p">,</span><span class="n">array2</span><span class="p">,</span><span class="mf">0.1</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># with a tolerance of 0.2, it should return True:</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">allclose</span><span class="p">(</span><span class="n">array1</span><span class="p">,</span><span class="n">array2</span><span class="p">,</span><span class="mf">0.2</span><span class="p">))</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="clip">Clip()</h2>
<p>使得一个数组中的数值保持在一个区间内。有时，我们需要保证数值在上下限范围内。为此，我们可以借助 Numpy 的 clip() <br>函数实现该目的。给定一个区间，则区间外的数值被剪切至区间上下限（interval edge）。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mi">3</span><span class="p">,</span> <span class="mi">17</span><span class="p">,</span> <span class="mi">14</span><span class="p">,</span> <span class="mi">23</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">16</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="n">np</span><span class="o">.</span><span class="n">clip</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">5</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="extract">extract()</h2>
<p>顾名思义，extract() 是在特定条件下从一个数组中提取特定元素。
借助于 extract()，我们还可以使用 and 和 or 等条件。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">array</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="mi">12</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;basic array is </span><span class="si">{}</span><span class="s1"> &#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">array</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1">#  Divide by 2 and check if remainder is 1</span>
</span></span><span class="line"><span class="cl"><span class="n">cond</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">mod</span><span class="p">(</span><span class="n">array</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">==</span><span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;是否符合条件的list，条件list</span><span class="se">\n</span><span class="s1">  </span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">cond</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Use extract to get the values</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 提取出表现为True的哪些元素</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;按照条件提取出元素:</span><span class="se">\n</span><span class="s1"> </span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">extract</span><span class="p">(</span><span class="n">cond</span><span class="p">,</span> <span class="n">array</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Apply condition on extract directly</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 更直接的指定条件</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;复杂条件下的表现情况&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">extract</span><span class="p">(((</span><span class="n">array</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">array</span> <span class="o">&gt;</span> <span class="mi">15</span><span class="p">)),</span> <span class="n">array</span><span class="p">))</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="where">where()</h2>
<p>Where() 用于从一个数组中返回满足特定条件的元素。比如，它会返回满足特定条件的数值的索引位
Where() 与 SQL 中使用的 where condition 类似，如以下示例所示：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">y</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">,</span><span class="mi">8</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">7</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">6</span><span class="p">,</span><span class="mi">9</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Where y is greater than 5, returns index position</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="n">y</span><span class="o">&gt;</span><span class="mi">5</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1"># First will replace the values that match the condition,</span>
</span></span><span class="line"><span class="cl"><span class="c1"># second will replace the values that does not</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="n">y</span><span class="o">&gt;</span><span class="mi">5</span><span class="p">,</span> <span class="s2">&#34;Hit&#34;</span><span class="p">,</span> <span class="s2">&#34;Miss&#34;</span><span class="p">))</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h1 id="debug">DEBUG</h1>
<p>记录一些典型错误，便于后续Debug的时候查找原因</p>
<h2 id="避免重复冲突的import">避免重复/冲突的import</h2>
<p>在工程实现中，对于同一个module。最好能做到<strong>不需要重复的import</strong>，但是在跨文件的工程项目中，或者说是一些跨文件调用的情况下，可能有一些基本的module会需要这样的时候，那我们最好做到<strong>不冲突</strong>，以同样的形式来进行import，不然有时候这样的重定义方式会出现一定的问题或者bug。
for example <code>from time import time</code> 和 <code>import time</code>同时出现的情况。</p>
<h2 id="内存调用与method的定义">内存调用与Method的定义</h2>
<p>在较为复杂的工程项目中，应该使用Method（Function）模块化的解决问题；这样做的优势可以从一下几点来看：</p>
<ol>
<li>易于阅读分析，写好相关method的Doc，然后做好注释，方便阅读和后续修改</li>
<li>能够在迭代过程中有效的释放暂态的变量，节约在主进程中无效的参数存储空间，节省内存或者显存。</li>
</ol>
<h2 id="typeerror">TypeError：</h2>
<p>一：<strong>cannnot unpack not-iterable NoneType object</strong>（无法解包非迭代类型的NoneType对象）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">test</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">value</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">a</span><span class="o">=</span><span class="n">b</span><span class="o">=</span><span class="mi">1</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span>
</span></span><span class="line"><span class="cl"><span class="n">a</span><span class="p">,</span><span class="n">b</span> <span class="o">=</span> <span class="n">test</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>原因分析</strong>，当python函数没有确定的return的时候默认的返回值是None，这样在进行检查的时候，就会到导致编译的错误</p>
<p><strong>解决</strong>：指定默认的return，或者使用else方法完善所有情况下的return值的个数是一致的</p>
<p>二：<strong>missing 1 required positional argument： “self”</strong></p>
<p>对象的声明需要括号，我们可能在调用类内函数的时候，用错了变量，用了<strong>类而不是类的实例</strong>去调用这个函数，导致执行出现了错误。</p>
<p>三：<strong>builtin_function_or_method  error</strong></p>
<p>很多时候都是由于前面的数据操作少加了<code>()</code>导致的问题</p>
<p>四：<strong>bad operand type for unary -: ‘NoneType’</strong></p>
<p>输入的数据存在着值为空的情况，可能没定义之类的，问题要根据后面的具体报错来进行分析。</p>
]]></content:encoded>
    </item>
    <item>
      <title>VsCode&#39;s Configuration</title>
      <link>https://aikenh.cn/posts/vscode/</link>
      <pubDate>Wed, 27 Oct 2021 14:19:13 +0000</pubDate>
      <guid>https://aikenh.cn/posts/vscode/</guid>
      <description>Some configurations of VsCode</description>
      <content:encoded><![CDATA[<h2 id="编辑相关设置">编辑相关设置</h2>
<h3 id="自定义分词机制">自定义分词机制</h3>
<p>当我们选择变量的时候，往往希望双击能够选中整个文本，但是由于分词机制，例如 <code>pre-word</code> 双击的话会被 <code>-</code> 划分为两个单词，这种时候可能不是我们希望的，VsCode 支持我们自定义这些分隔符，我们可以将其 <code>-</code> 从设置中删除即可</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240420172643.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240420172643.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20240420172643.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="终端部分的输出双击复制">终端部分的输出双击复制</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>json</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="s2">&#34;terminal.integrated.copyOnSelection&#34;</span><span class="err">:</span> <span class="kc">true</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="禁止通过拖放来移动选择内容">禁止通过拖放来移动选择内容</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>json</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="s2">&#34;editor.dragAndDrop&#34;</span><span class="err">:</span> <span class="kc">false</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="launch-文件配置">Launch 文件配置</h2>
<p>配置Launch.json 能够帮助我们更好的进行debug的操作，有一些比较特别的文件名和相关编码。</p>
<ul>
<li><code>${workspaceFolder}</code> 指代当前运行目录</li>
<li><code>${file}</code>指代当前文件</li>
</ul>
<p>找到launch文件并打开，自定义JSON：执行工作文件夹下的main.py进行调试。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>json</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;experiment&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;python&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;request&#34;</span><span class="p">:</span> <span class="s2">&#34;launch&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;program&#34;</span><span class="p">:</span> <span class="s2">&#34;${workspaceFolder}/main.py&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;console&#34;</span><span class="p">:</span> <span class="s2">&#34;integratedTerminal&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;--data_path&#34;</span><span class="p">,</span><span class="s2">&#34;${workspaceFolder}/data&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;--mode&#34;</span><span class="p">,</span><span class="s2">&#34;0&#34;</span><span class="p">,</span><span class="s2">&#34;--resume&#34;</span><span class="p">,</span><span class="s2">&#34;false&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span><span class="err">,</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>默认 JSON：执行当前文件</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>json</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;current file&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;python&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;request&#34;</span><span class="p">:</span> <span class="s2">&#34;launch&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;program&#34;</span><span class="p">:</span> <span class="s2">&#34;${file}&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;console&#34;</span><span class="p">:</span> <span class="s2">&#34;integratedTerminal&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="snippets">Snippets</h2>
<p>学会编写VsCode的用户代码片段，实际上也就是snippets，在我们编写代码的时候用来输出。</p>
<p>例子：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>json</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="c1">// Place your snippets for cpp here. Each snippet is defined under a snippet name and has a prefix, body and 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the 
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// same ids are connected.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// Example:
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// &#34;Print to console&#34;: {
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// 	&#34;prefix&#34;: &#34;log&#34;,
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// 	&#34;body&#34;: [
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// 		&#34;console.log(&#39;$1&#39;);&#34;,
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// 		&#34;$2&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// 	],
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// 	&#34;description&#34;: &#34;Log output to console&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// }
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nt">&#34;Print to console&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nt">&#34;prefix&#34;</span><span class="p">:</span> <span class="s2">&#34;tencent-header&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nt">&#34;body&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;/*===============================================================&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;*   Copyright (C) 2019 Tencent Technology Company Limited.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;*&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;*   Name：$TM_FILENAME&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;*   Author：aikenhong@tencent.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;*   Date：$CURRENT_YEAR年$CURRENT_MONTH月$CURRENT_DATE日&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;*   Desc：$1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;*&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;*   Update History：&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;*&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;================================================================*/&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;#ifndef $TM_FILENAME&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;#define $TM_FILENAME&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;#pragma once&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;#include &lt;map&gt;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;#include &lt;math.h&gt;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;#include &lt;string&gt;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;#include &lt;studio.h&gt;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;#include \&#34;label_helper.h\&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;#include \&#34;feature_select.h\&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;#include \&#34;sgame_ai_src/common/util.h\&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;#include \&#34;sgame_ai_src/common/target_finder.h\&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">			<span class="s2">&#34;#include \&#34;game_ai_src/tactics/tactics_multi_task_two_hand_action.h\&#34;&#34;</span>
</span></span><span class="line"><span class="cl">		<span class="p">],</span>
</span></span><span class="line"><span class="cl">		<span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;header for the humanlike indicator development&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>其中<code> $&lt;number&gt;</code> 是按下光标后跳转的位置，<code>$ &lt;keyword&gt;</code> 可以有诸多表达式，建议去上网查一下。</p>
<h2 id="todo-tree">Todo Tree</h2>
<p>打开设置-打开json文件（设置右上角）</p>
<p>添加如下内容：（颜色和关键词可自定义）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>json</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="s2">&#34;todo-tree.tree.showScanModeButton&#34;</span><span class="err">:</span> <span class="kc">true</span><span class="err">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;todo-tree.highlights.enabled&#34;</span><span class="err">:</span> <span class="kc">true</span><span class="err">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;todo-tree.highlights.defaultHighlight&#34;</span><span class="err">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;text and comment&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span><span class="err">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;todo-tree.highlights.customHighlight&#34;</span><span class="err">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;TODO&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;foreground&#34;</span><span class="p">:</span> <span class="s2">&#34;#2f3542&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;background&#34;</span><span class="p">:</span> <span class="s2">&#34;#f6b93b&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;iconColour&#34;</span><span class="p">:</span> <span class="s2">&#34;#f39c12&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;icon&#34;</span><span class="p">:</span> <span class="s2">&#34;issue-opened&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;line&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;FIXME&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;foreground&#34;</span><span class="p">:</span> <span class="s2">&#34;#2f3542&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;background&#34;</span><span class="p">:</span> <span class="s2">&#34;#e55039&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;iconColour&#34;</span><span class="p">:</span> <span class="s2">&#34;#e55039&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;icon&#34;</span><span class="p">:</span> <span class="s2">&#34;flame&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;line&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;NOTE&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;foreground&#34;</span><span class="p">:</span> <span class="s2">&#34;#2f3542&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;background&#34;</span><span class="p">:</span> <span class="s2">&#34;#9980FA&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;iconColour&#34;</span><span class="p">:</span> <span class="s2">&#34;#6c5ce7&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;icon&#34;</span><span class="p">:</span> <span class="s2">&#34;eye&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;line&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;RECORD&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;foreground&#34;</span><span class="p">:</span> <span class="s2">&#34;#2f3542&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;background&#34;</span><span class="p">:</span> <span class="s2">&#34;#7bed9f&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;iconColour&#34;</span><span class="p">:</span> <span class="s2">&#34;#2ed573&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;icon&#34;</span><span class="p">:</span> <span class="s2">&#34;info&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;line&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span><span class="err">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;todo-tree.general.tags&#34;</span><span class="err">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;TODO&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;FIXME&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;NOTE&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;RECORD&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span><span class="err">,</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="plugins">Plugins</h2>
<p>introduce some plugins or special usage</p>
<h3 id="monokai-pro">Monokai Pro</h3>
<p>切换到目录<code>user/aiken/.vscode/extensions/monokaipro/js/app.js</code> 类似的文件，</p>
<p>找到<code>key: &quot;isValidLicense&quot;</code></p>
<p>将下方的<code>if</code>和<code>return</code>的判定值1即可</p>
<p>最终代码如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>js</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">key</span><span class="o">:</span> <span class="s2">&#34;isValidLicense&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="nx">value</span><span class="o">:</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nx">e</span> <span class="o">=</span> <span class="nx">arguments</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="k">void</span> <span class="mi">0</span> <span class="o">!==</span> <span class="nx">arguments</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">?</span> <span class="nx">arguments</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">t</span> <span class="o">=</span> <span class="nx">arguments</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="o">&amp;&amp;</span> <span class="k">void</span> <span class="mi">0</span> <span class="o">!==</span> <span class="nx">arguments</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">?</span> <span class="nx">arguments</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">:</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">e</span> <span class="o">||</span> <span class="o">!</span><span class="nx">t</span><span class="p">)</span> <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nx">o</span> <span class="o">=</span> <span class="nx">s</span><span class="p">()(</span><span class="s2">&#34;&#34;</span><span class="p">.</span><span class="nx">concat</span><span class="p">(</span><span class="nx">i</span><span class="p">.</span><span class="nx">APP</span><span class="p">.</span><span class="nx">UUID</span><span class="p">).</span><span class="nx">concat</span><span class="p">(</span><span class="nx">e</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">        <span class="nx">r</span> <span class="o">=</span> <span class="nx">o</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="sr">/.{1,5}/g</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">        <span class="nx">n</span> <span class="o">=</span> <span class="nx">r</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">).</span><span class="nx">join</span><span class="p">(</span><span class="s2">&#34;-&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">t</span> <span class="o">===</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="list">List</h3>
<p>列出已经安装的插件列表可以靠以下的命令：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">code --list-extensions &gt; extensions.txt</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>插件列表和配置文件可以在我的 <a href="https://github.com/AikenH/aikenh-dotfile/blob/main/vscode/extensions.txt" target="_blank" rel="noopener">dotfile</a>
 仓库获取。</p>
]]></content:encoded>
    </item>
    <item>
      <title>Vim 00 Basic Opeation</title>
      <link>https://aikenh.cn/posts/vimtutor/</link>
      <pubDate>Thu, 14 Oct 2021 01:58:22 +0000</pubDate>
      <guid>https://aikenh.cn/posts/vimtutor/</guid>
      <description>vim&amp;#39;s basic operation</description>
      <content:encoded><![CDATA[<p>this is the Note record the vimtutor (the basic usage of vim.)
@Aiken 2021</p>
<ul>
<li>write some word and we can use shift+a to insert in the end.
<a href="https://github.com/HanielF/VimTutor" target="_blank" rel="noopener">the doc with Chinese</a>
</li>
</ul>
<!-- vim-markdown-toc GFM -->
<ul>
<li><a href="#delete-command">delete command</a>
</li>
<li><a href="#skip-words-and-lines">skip words and lines</a>
</li>
<li><a href="#undo-and-resume">undo and resume</a>
</li>
<li><a href="#replace-and-change">replace and change</a>
</li>
<li><a href="#location-and-file-status">location and file status</a>

<ul>
<li><a href="#search-command">search command</a>
</li>
<li><a href="#find-the-matched-parentheses-%e6%89%be%e5%88%b0%e5%af%b9%e5%ba%94%e7%9a%84%e6%8b%ac%e5%8f%b7">find the matched parentheses 找到对应的括号</a>
</li>
<li><a href="#substitute-command-%e6%9b%bf%e6%8d%a2%e5%91%bd%e4%bb%a4">substitute command 替换命令</a>
</li>
</ul>
</li>
<li><a href="#execute-an-ecternal-command">EXECUTE AN ECTERNAL COMMAND</a>
</li>
<li><a href="#the-open-command">THE OPEN COMMAND</a>
</li>
<li><a href="#copy-and-paste">COPY AND PASTE</a>
</li>
<li><a href="#set-option">SET OPTION</a>
</li>
<li><a href="#keyshort">KEYSHORT</a>
</li>
</ul>
<!-- vim-markdown-toc -->
<h2 id="delete-command">delete command</h2>
<p>Most of the command can use <code>NUM</code> to repeat it.
<code>d num</code> command means delete <code>num</code> times with args below:
<code>c</code> means del and change mode to insert:</p>
<ul>
<li>w delete next num words</li>
<li>e delete cur word</li>
<li>d delete this line which is not support &lsquo;c&rsquo;</li>
<li>$ delete to the end of the line</li>
</ul>
<p>x means delete this cur</p>
<h2 id="skip-words-and-lines">skip words and lines</h2>
<p><code>e</code> means jump the end of the word
<code>3e</code>: means skip 3word distance
<code>2w</code>: means skip 2word
the <code>num</code> can be decide by ourself.(in the most commands)</p>
<h2 id="undo-and-resume">undo and resume</h2>
<p><code>u</code> means undo.
<code>U</code> undo the line.</p>
<p><code>ctrl+r</code> means resume which is contrast undo.</p>
<h2 id="replace-and-change">replace and change</h2>
<p><code>r</code> replace char with new input
<code>R</code> become replace mode, replace word by input util we press esc</p>
<h2 id="location-and-file-status">location and file status</h2>
<p><code>ctrl+g</code> will show the location in file and the file status.</p>
<ul>
<li><code>gg</code>: move to the head of the file.</li>
<li><code>G</code>: move to the end of the file.</li>
<li><code>idx + G</code>: jump 2 the line.</li>
<li><code>shift+6</code>: jump 2 the head of the line.</li>
</ul>
<h3 id="search-command">search command</h3>
<ol>
<li>typing: <code>/</code> &lt;word_we_want&gt; to search it.</li>
<li>if we want to search same word, just type <code>n</code>, in another order <code>N</code></li>
<li>using ctrl+o to go back the cursor location, ctrl+i to go next</li>
<li>using <code>?</code> instand of <code>/</code> if we want search in the inverse order.</li>
</ol>
<h3 id="find-the-matched-parentheses-找到对应的括号">find the matched parentheses 找到对应的括号</h3>
<p>typing <code>%</code> near the ( { [, it&rsquo;ll jump to another.
this is very useful in debugging a program</p>
<h3 id="substitute-command-替换命令">substitute command 替换命令</h3>
<ul>
<li>
<p>:idx0,idx1s/old/new/g
replace old with new in the line between [idx0,idx1]</p>
</li>
<li>
<p>:%s/old/new/g
replace all the old with new in whold file</p>
</li>
<li>
<p>:%s/old/new/gc
find out all old and we willdecide change it or not manually.</p>
</li>
</ul>
<h2 id="execute-an-ecternal-command">EXECUTE AN ECTERNAL COMMAND</h2>
<p>how to execute an command like shell command?</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">using :!<span class="o">[</span>command<span class="o">]</span> -<span class="o">[</span>args<span class="o">]</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>:w [filename] can save this file in this position or save change or it.</li>
<li>:!rm [filename]</li>
<li>:v choose those text or code we want to save(not all this file,
just what we selected) and :w [filename] to save it</li>
<li>:r [filename] will resume the txt of the file in this cursor.</li>
<li>:r !dir will read the command output and puts it below the cursor</li>
</ul>
<h2 id="the-open-command">THE OPEN COMMAND</h2>
<ul>
<li><code>o</code> means will insert a line UNDER the cursor</li>
<li><code>O</code> will insert ABOVE the cursor</li>
</ul>
<h2 id="copy-and-paste">COPY AND PASTE</h2>
<ul>
<li><code>y</code> copy command.</li>
<li><code>yw</code> copy a word</li>
<li><code>p</code> paste(put) command</li>
<li><code>v</code> visual mode, select those char we want.</li>
<li><code>$</code> jump to the end of the line</li>
</ul>
<h2 id="set-option">SET OPTION</h2>
<p>set an option so a search or subsititute ignore case</p>
<ul>
<li>after type in &lsquo;:/ignore&rsquo;</li>
<li>then type in <code>::set ic</code> will ignore case</li>
<li><code>:set is</code> 部分显示匹配的搜索短语</li>
<li><code>:set hls</code> 高亮显示所有匹配的短语</li>
<li><code>:set no+&lt;command&gt;</code> 前置no可以关闭选项</li>
</ul>
<h2 id="keyshort">KEYSHORT</h2>
<ol>
<li>Ctrl + f/b : 往下/上翻页</li>
<li>Ctrl + e/y : 往下/上滚动</li>
<li>V: 列选择模式</li>
<li>U/u: 选中的单词变成大/小写</li>
<li>Ctrl + w: 光标窗口切换</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>Vim Configuration 03 Spacevim Setup</title>
      <link>https://aikenh.cn/posts/spacevim/</link>
      <pubDate>Sat, 09 Oct 2021 12:15:41 +0000</pubDate>
      <guid>https://aikenh.cn/posts/spacevim/</guid>
      <description>Install and Set up LSP and UI</description>
      <content:encoded><![CDATA[<p>@Aiken 2021 this file is use to record how to config out vim&rsquo; by spacevim.<br>
I&rsquo;ll write this doc with three Parts:</p>
<ul>
<li>Install and envs, Plugins(including the LSP), KeyShort</li>
<li>Attention: we have much to do if we want to install some other plugins.
maybe it not a good way to set the vim.</li>
</ul>
<!-- vim-markdown-toc GFM -->
<ul>
<li><a href="#install-spacevim-and-config-it">INSTALL SPACEVIM AND CONFIG IT</a>
</li>
<li><a href="#install-langs">INSTALL LANGs&rsquo;</a>

<ul>
<li><a href="#cocnvim">COCNVIM</a>
</li>
</ul>
</li>
<li><a href="#keyshort-and-special-usage">KEYSHORT and special USAGE</a>

<ul>
<li><a href="#split-windows-and-checkout">SPLIT WINDOWS and CHECKOUT</a>
</li>
</ul>
</li>
<li><a href="#plugins">Plugins</a>
</li>
</ul>
<!-- vim-markdown-toc -->
<hr>
<h2 id="install-spacevim-and-config-it">INSTALL SPACEVIM AND CONFIG IT</h2>
<p><strong>Install:</strong> SpaceVim via the offical websize:</p>
<ul>
<li><a href="https://spacevim.org/cn/quick-start-guide/" target="_blank" rel="noopener">spacevim</a>
</li>
<li><a href="https://spacevim.org/cn/layers/" target="_blank" rel="noopener">layers</a>
</li>
<li><a href="https://spacevim.org/cn/layers/colorscheme/" target="_blank" rel="noopener">colorscheme</a>
</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">The COMMAND is like:
</span></span><span class="line"><span class="cl">curl -sLf https://spacevim.org/cn/install.sh <span class="p">|</span> bash</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>After that, the spacevim will install for the vim and neovim.</p>
<p><strong>Basic Configuration:</strong></p>
<ol>
<li>
<p>modify the spacevim configuration in the file below
<code>~/.SpaceVim.d/init.toml</code></p>
</li>
<li>
<p>And enable some layers we need: which can select from <code>spc + h + l</code>
after enable those layer, <strong>DEIN</strong> will install those plugins
we need use GLOBAL VPN to download plugins.</p>
</li>
<li>
<p>something like <code>set: wrap</code> will be add in <code>~/.SpaceVim/vimrc</code> (end of it)</p>
</li>
</ol>
<h2 id="install-langs">INSTALL LANGs'</h2>
<p>This is the most important part for coding: lint,autocomplete,warning..<br>
At the same time, this part is hardest to install,
because the coc.nvim which is not design for spacevim.</p>
<p><strong>FIRST OF ALL:</strong> enable those langs&rsquo; layer: python(first), markdown, c++;<br>
We can install those module according to the Docs,
then install sth like pynvim(pip), node js, yarn, neovim, make&hellip;<br>
<strong>THEN:</strong> run <code>:CheckHealth</code> after install coc to check the env status.<br>
<strong>NEXT:</strong> try install debug, c++, c, for the future dev.</p>
<h3 id="cocnvim">COCNVIM</h3>
<p>Using Python As a example to show how to install this.<br>
Hardest Part here: <a href="https://zhuanlan.zhihu.com/p/137840336" target="_blank" rel="noopener">CPP with Coc</a>
,
<a href="https://github.com/neoclide/coc.nvim/wiki/Install-coc.nvim#using-vim-plug" target="_blank" rel="noopener">Coc Offical</a>
<br>
<a href="https://github.com/SpaceVim/SpaceVim/issues/2564" target="_blank" rel="noopener">Coc_issues</a>
</p>
<ul>
<li>Install nodejs and yarn:</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># add &amp; update apt source before install nodejs.</span>
</span></span><span class="line"><span class="cl">curl -sL https://deb.nodesource.com/setup_14.x <span class="p">|</span> sudo -E bash -
</span></span><span class="line"><span class="cl">sudo apt-get update
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># install nodejs after that.</span>
</span></span><span class="line"><span class="cl">sudo apt-get install -y nodejs
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># install yarn in shell refer to the hint</span>
</span></span><span class="line"><span class="cl">like: 
</span></span><span class="line"><span class="cl">curl --compressed -o- -L https://yarnpkg.com/install.sh <span class="p">|</span> bash</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>Install Coc in SpaceVim by dein in init.toml:</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>yaml</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="p">[</span><span class="l">options]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="l">autocomplete_method = &#39;coc&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">[[</span><span class="l">layers]]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="l">name = &#39;lsp&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="l">filetype = [</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="s1">&#39;c&#39;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="s1">&#39;cpp&#39;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="s1">&#39;dart&#39;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">[</span><span class="l">layers.override_cmd]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="l">c = [&#39;ccls&#39;]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="l">cpp = [&#39;ccls&#39;]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="l">python = [&#39;pyls&#39;]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">[[</span><span class="l">cusiom_plugins]]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="l">repo = &#34;neoclide/coc.nvim&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="l">merge = 0</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="l">rev = &#39;release&#39;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>after install using <code>:checkhealth</code> &lsquo;CocInfo&rsquo; to comfirm.</p>
<ul>
<li>Install some basic part(jedi):</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">conda install jedi
</span></span><span class="line"><span class="cl">:CocInstall coc-jedi coc-python coc-snippets 
</span></span><span class="line"><span class="cl">:CocInstall coc-python
</span></span><span class="line"><span class="cl">:CocInstall coc-clangd</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>coc_keyword:</strong>
some basic coc command we may use often</p>
<ul>
<li><code>CocInstall [PackageName]</code></li>
<li><code>CocUninstall [PackageName]</code></li>
</ul>
<h2 id="keyshort-and-special-usage">KEYSHORT and special USAGE</h2>
<ul>
<li>reinstall some plugins can use: <code>SPReinstall coc.nvim</code>.</li>
<li>running/debug info will record in <code>SPDebugInfo</code></li>
<li>to_tree will show in <code>spc a o</code> after we save the modify of file</li>
</ul>
<h3 id="split-windows-and-checkout">SPLIT WINDOWS and CHECKOUT</h3>
<p>split windows to show more info and make it easily to code.</p>
<ul>
<li><code>sp [filename]</code> to splite windows with new files. u-d</li>
<li><code>vsp [filename]</code> to splite windows with new files. l-r</li>
<li><code>spc [num]</code> checkout cursor in diff windows</li>
<li><code>g t</code> checkout from tag to tag</li>
</ul>
<h2 id="plugins">Plugins</h2>
<p>This part is depending the <code>DEIN</code>, so we can reference this plugins.
Many useful plugins had been add in those layers, learn it from offical website.</p>
<ol>
<li><a href="https://zhuanlan.zhihu.com/p/58816186" target="_blank" rel="noopener">recommand1</a>
</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>SS_OD_SoftTeacher</title>
      <link>https://aikenh.cn/posts/ss_od_softteacher/</link>
      <pubDate>Sat, 09 Oct 2021 02:30:08 +0000</pubDate>
      <guid>https://aikenh.cn/posts/ss_od_softteacher/</guid>
      <description>Semi-Supervised Object Detection with Soft Teacher</description>
      <content:encoded><![CDATA[<p>@ Article: ICML from Microsoft &amp; Huazhong Keda
@ Code: <a href="https://github.com/microsoft/SoftTeacher" target="_blank" rel="noopener">Github</a>

@ Noteby: Aikenhong
@ Time: 20210914</p>
<h2 id="abstrast-and-intro">Abstrast and Intro</h2>
<p>in the session we will using describe the main idea of this article.</p>
<p>这篇文章的重点在于Soft Teacher，也就是用pseudo label做为弱标注，逐步提高伪标签的可靠性。</p>
<p>不同于多阶段的方法，端到端的方法再训练中逐步的提升伪标签的质量从而再去benifit目标检测的质量。
这样E2E的框架主要依赖于两部分技术:</p>
<ul>
<li>soft teacher: 每个未标记边界框的分类损失由教师网络产生的分类分数进行加权</li>
<li>box jitter 窗口抖动: 选择可靠的伪框来学习框回归</li>
</ul>
<p>在目标检测上获得SOTA的效果;</p>
<h3 id="multi-stage">Multi-Stage</h3>
<p>在半监督的情况下，关注的主要是基于伪标签的方法，是目前的SOTA，以往的方法采用多阶段的方式。</p>
<ol>
<li>使用标记数据训练初始检测器</li>
<li>未标记数据的伪标记，同时基于伪标签进行重新训练</li>
</ol>
<p><strong>局限</strong>：初始少量标注的局限，初始的检测器的伪标签质量</p>
<h3 id="end-to-end">End to End</h3>
<p><strong>Soft Teacher</strong>基本思路：对未标记的图像进行标记，然后通过标记的几个伪标签训练检测器.</p>
<p>具体而言：</p>
<ol>
<li>采样标注和未标注图片形成Batch</li>
<li>双模型：检测（student）、标记（teacher）</li>
<li>EMA：T模型是S模型的EMA</li>
</ol>
<p>这种方式避免了多阶段方案实现上的复杂，同时实现了飞轮效应==S、T相互加强;</p>
<p><strong>此外Soft Teacher</strong>直接对学生模型生成的所有候选框进行评估，而不是使用伪框来为这些候选框进行分类回归。
这样能使用更多的直接监督信息</p>
<p>具体而言：</p>
<ol>
<li>使用高阈值来分割前景，确保不会错误的将背景分类成前景，确保正伪标签的高精度；</li>
<li>使用可靠性度量来加权背景候选的损失；</li>
<li>教师模型产生的检测分数可以很好的作为可靠性度量</li>
</ol>
<p><strong>Box Jitter</strong>为了更可靠的训练学生网络的本地分支，指的是：</p>
<ul>
<li>我们对前景框候选进行多次抖动</li>
<li>根据教师模型的位置分支对这些候选进行回归</li>
<li>将回归框的方差作为可靠性度量</li>
<li>可靠性高的用来训练</li>
</ul>
<h2 id="related-works">Related works</h2>
<p><strong>Semi-Supervised Learning in Image Classification &amp; object detection</strong></p>
<ul>
<li>consistency based</li>
<li>pesudo-label based</li>
</ul>
<p>new idea：使用弱数据增强生成伪标签和强增强来学习检测模型，区分两部分工作</p>
<p><strong>Object Detection</strong></p>
<p>Based on Faster R-CNN to compare with other method</p>
<h2 id="methodology">Methodology</h2>
<p>可以从下面的图中看出基础的实现逻辑：</p>
<h3 id="framework">Framework</h3>
<p><strong>训练（Loss）是基于Batch进行</strong>，对于标记数据和未标记数据的损失处理时分开的， 对于未标记数据，我们需要通过教师模型来得到一个softlabel，包括分类和回归两个任务，然后得到最终的损失值。</p>
<div>
$$ 
L = L_s + \alpha L_u
 $$
</div>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210914155109.png">
    <img alt="image-20210914152516997" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210914155109.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210914155109.png" style="display: block; margin: 0 auto;"
      alt="image-20210914152516997"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>两者都要通过各自的图像数量进行归一化，以标注数据为例</p>
<div>
$$ 
L_s = \frac{1}{N_l}\sum_{i=1}^{N_l}(L_{cls}(I_l^i)+(L_{reg}(I_l^i))
 $$
</div>
<p><strong>如何启动教师模型：</strong></p>
<p>随机初始化学生模型和教师模型，后续通过学生模型的EMA来进行教师模型的更新。</p>
<p><strong>目标检测的伪标签定义</strong>：</p>
<p>教师模型检测后NMS消除冗余，然后使用阈值来抑制非前景的候选；</p>
<p><strong>获取高质量的伪标签：</strong></p>
<p>对教师模型的伪标记使用弱增强，学生模型训练使用强增强</p>
<h3 id="soft-teacher">Soft Teacher</h3>
<p>检测器的性能取决于伪标签的质量，如果在前景分数上使用较高的阈值过滤掉大部分学生生成的低置信度候选框可以得到更好的结果，当阈值设置为0.9时性能最佳，但是召回率迅速下降。</p>
<ul>
<li>一般方法：使用学生生成的候选框和教师生成的候选框的IoU来分配前景和背景，可能会损坏性能。</li>
<li>软教师：我们评估学生生成的候选框作为真实背景的可靠性，用于衡量背景分类损失；</li>
</ul>
<div>
$$ b^{fg}_i $$
</div>
 、 
<div>
$$ b^{bg}_i $$
</div>
 分别是分配为前景的框和分配为背景的框，具有可靠权重的伪标记图像的分类损失定义为：
<div>
$$ 
\mathcal{L}_{u}^{\mathrm{cls}}=\frac{1}{N_{b}^{\mathrm{fg}}} \sum_{i=1}^{N_{b}^{\mathrm{fg}}} l_{\mathrm{cls}}\left(b_{i}^{\mathrm{fg}}, \mathcal{G}_{\mathrm{cls}}\right)+\sum_{j=1}^{N_{b}^{\mathrm{b}_{b}}} w_{j} l_{\mathrm{cls}}\left(b_{j}^{\mathrm{bg}}, \mathcal{G}_{\mathrm{cls}}\right)
 $$
</div>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210914165535.png">
    <img alt="image-20210914165532071" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210914165535.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210914165535.png" style="display: block; margin: 0 auto;"
      alt="image-20210914165532071"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<div>
$$ 
w_j = \frac{\gamma_j}{\sum_{k=1}^{N_b^{bg}}\gamma_k}
 $$
</div>
<div>
$$ \mathcal{G}_{cls} $$
</div>
 表示用于分类（教师生成的）伪框集， 
<div>
$$ l_{cls}() $$
</div>
 是框分类损失， 
<div>
$$ r_j $$
</div>
 是第j个背景的可靠性分数；
<p>我们通过教师模型产生的背景分数可以很好的代替可靠性：</p>
<ul>
<li>使用教师模型（BG-T）通过检测头来获取样本的背景分数</li>
</ul>
<p>还研究了：学生模型，学生模型和学生模型之间的差异</p>
<h3 id="box-jittering">Box Jittering</h3>
<p>图三b可以看到，候选框的定义准确率和前景分数不是一个正相关的关系，他不一定能提供准确的定位信息。</p>
<p>需要更好的候选框，在教师生成的候选框bi上做抖动采样，将抖动框输入教师模型获得调整后的框</p>
<div>
$$ 
\hat{b_i} = refine(jitter(b_i)).
 $$
</div>
<p>抖动 $N_{jittle}$ 次后得到 ${\hat{b}_{i,j}}$ 集合，然后将可靠性定义为box回归方差：</p>
<div>
$$ 
\overline{\sigma}_i = \frac{1}{4}\sum_{k=1}^4\hat{\sigma}_k
 $$
</div>
<p>其中：</p>
<div>
$$ 
\hat{\sigma}_k = \frac{\sigma_k}{0.5(h(b_i)) + w(b_i)}
 $$
</div>
<p>较小的框回归方差表示较高的本地可靠性，但是大量的计算也是不可忍受的，所以我们一般只计算前景分数大于0.5的框的可靠性</p>
<p><strong>回归方差计算</strong>：</p>
<div>
$$ 
\mathcal{L}_{u}^{\mathrm{rcg}}=\frac{1}{N_{b}^{\mathrm{fg}}} \sum_{i=1}^{N_{b}^{\mathrm{f}_{8}}} l_{\mathrm{reg}}\left(b_{i}^{\mathrm{fg}}, \mathcal{G}_{\mathrm{reg}}\right)
 $$
</div>
<div>
$$ 
\mathcal{L}_{u}=\frac{1}{N_{u}} \sum_{i=1}^{N_{u}}\left(\mathcal{L}_{u}^{\mathrm{cls}}\left(I_{u}^{i}, \mathcal{G}_{\mathrm{cls}}^{i}\right)+\mathcal{L}_{u}^{\mathrm{rcg}}\left(I_{u}^{i}, \mathcal{G}_{\mathrm{rcg}}^{i}\right)\right)
 $$
</div>
<h3 id="experiment">Experiment</h3>
<p>实验细节</p>
]]></content:encoded>
    </item>
    <item>
      <title>Vim Configuration 02 Nvim的插件配置</title>
      <link>https://aikenh.cn/posts/vimconfig/</link>
      <pubDate>Fri, 08 Oct 2021 07:45:42 +0000</pubDate>
      <guid>https://aikenh.cn/posts/vimconfig/</guid>
      <description>Using Vimscript to deploy my nvim(&amp;lt;=0.5)</description>
      <content:encoded><![CDATA[<p>@Aikenhong 2021</p>
<p>Vim is a important consistant for editing file in shell. It&rsquo;s Hightly Customized for Everyone, In this part I&rsquo;ll Show my personal Vim comfigurations</p>
<p>And I&rsquo;ll Discuss about the diff between Spacevim &amp; Neovim.</p>
<p>Give a conclusion in advance: <strong>Recommand Config the Vim for Yourself</strong></p>
<ul>
<li>You only need to config once, then you should save it in the cloud.</li>
<li>You will Know all the Keyshot you setting up, and you can customize it as you want.</li>
</ul>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20211014192437083.png">
    <img alt="image-20211014192437083" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20211014192437083.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20211014192437083.png" style="display: block; margin: 0 auto;"
      alt="image-20211014192437083"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="based-on-neovim">Based on neovim</h2>
<p>基于NeoVim进行配置，不采用SpaveVim的配置文件，这里需要建议采用最新的测试版的NeoVim(&gt;= 0.5)，Stable的NVim已经很久没有更新，对一些新的插件缺乏支持。</p>
<h3 id="install">Install</h3>
<p><a href="https://github.com/neovim/neovim/wiki/Installing-Neovim" target="_blank" rel="noopener">Installing Neovim </a>
 Download NeoVim Package and Install from source</p>
<p>or <a href="https://thomasventurini.com/articles/install-neovim-05-in-ubuntu/" target="_blank" rel="noopener">Install from neovim-ppa</a>
 Like Following:</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo add-apt-repository ppa:neovim-ppa/unstable
</span></span><span class="line"><span class="cl">sudo apt-get update
</span></span><span class="line"><span class="cl">sudo apt-get install neovim</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在安装了Python之后安装对NVim的适配</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">pip install neovim
</span></span><span class="line"><span class="cl">pip install pynvim</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>同时在配置文件中设置</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">let g:python3_host_prog</span><span class="o">=</span><span class="s">&#39;/home/aikenhong/anaconda3/bin/python&#39;</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; the path to your python&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>检查python配置情况：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">” check lang suppose for neovim</span>
</span></span><span class="line"><span class="cl"><span class="na">“ focus on the python part</span>
</span></span><span class="line"><span class="cl"><span class="na">:CheckHealth</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20211014195016009.png">
    <img alt="image-20211014195016009" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20211014195016009.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20211014195016009.png" style="display: block; margin: 0 auto;"
      alt="image-20211014195016009"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="update">Update</h3>
<p>if we Install the old version of neovim(5.0 which install before add ppa), we can update by apt.</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># add the stable or unstable source for new nvim</span>
</span></span><span class="line"><span class="cl">sudo add-apt-repository ppa:neovim-ppa/unstable
</span></span><span class="line"><span class="cl">sudo apt-get update
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># update your nvim</span>
</span></span><span class="line"><span class="cl">sudo apt-get install --only-upgrade neovim</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="where-is-config-file">Where is Config File</h3>
<p>可以在vim中使用<code>:version</code>然后在其中调用<code>:echo $MYVIMRC</code>查看对应的<code>vimrc</code>存放的地址</p>
<p><code>vim</code>的配置文件地址：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># this time is in</span>
</span></span><span class="line"><span class="cl">ls -l /etc/vim/vimrc
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># or we can touch one in</span>
</span></span><span class="line"><span class="cl">ls -l ~/.vim/vimrc</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><code>nvim</code>的配置文件的地址：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ls -l ~/.config/nvim/init.vim
</span></span><span class="line"><span class="cl"><span class="c1"># if not, touch one</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>有了配置文件以后就可以开始对Nvim进行配置</p>
<h2 id="basic-config">Basic Config</h2>
<p>this part I&rsquo;ll explain those basic configurations in Vim(NVim). Besides I will simplely introduce the syntax of <code>.ini</code> for writing config.</p>
<h3 id="basic-setting">Basic Setting</h3>
<p>nvim初始情况就是完全没有配置的记事本，但是相应的定制化程度高，下面这些是一些固定的配置</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">&#34;</span><span class="o">=</span><span class="s">==========================基本配置</span>
</span></span><span class="line"><span class="cl"><span class="na">set nowrap &#34; 不自动换行</span>
</span></span><span class="line"><span class="cl"><span class="na">set nu  &#34;显示行号</span>
</span></span><span class="line"><span class="cl"><span class="na">set clipboard</span><span class="o">=</span><span class="s">unnamed &#34;共享剪切板</span>
</span></span><span class="line"><span class="cl"><span class="na">set nocompatible &#34; 不适配vi避免不兼容</span>
</span></span><span class="line"><span class="cl"><span class="na">set backup &#34;生成临时文件（maybe we should make it no）</span>
</span></span><span class="line"><span class="cl"><span class="na">set noswapfile &#34; i dont like swap files</span>
</span></span><span class="line"><span class="cl"><span class="na">set history</span><span class="o">=</span><span class="s">1000</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="na">&#34; 文件在外部被修改过，就重新读入</span>
</span></span><span class="line"><span class="cl"><span class="na">set sessionoptions+</span><span class="o">=</span><span class="s">globals</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; 延迟绘制提升性能</span>
</span></span><span class="line"><span class="cl"><span class="na">set lazyredraw</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; 显示确认</span>
</span></span><span class="line"><span class="cl"><span class="na">set confirm</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="na">&#34;set paste</span>
</span></span><span class="line"><span class="cl"><span class="na">autocmd InsertLeave * set nopaste &#34;结束插入模式的时候关闭paste</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>配置搜索视图：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">&#34; 高亮搜索结果，逐词高亮</span>
</span></span><span class="line"><span class="cl"><span class="na">set hlsearch</span>
</span></span><span class="line"><span class="cl"><span class="na">set incsearch</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; 搜索忽视大小写</span>
</span></span><span class="line"><span class="cl"><span class="na">set ignorecase</span>
</span></span><span class="line"><span class="cl"><span class="na">set smartcase</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; 显示匹配的括号</span>
</span></span><span class="line"><span class="cl"><span class="na">set showmatch</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>配置Tab和Indent：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">” tab 和indent设置</span>
</span></span><span class="line"><span class="cl"><span class="na">set tabstop</span><span class="o">=</span><span class="s">4 &#34; Tab键的宽度</span>
</span></span><span class="line"><span class="cl"><span class="na">set expandtab</span>
</span></span><span class="line"><span class="cl"><span class="na">set smarttab</span>
</span></span><span class="line"><span class="cl"><span class="na">set shiftwidth</span><span class="o">=</span><span class="s">4</span>
</span></span><span class="line"><span class="cl"><span class="na">set autoindent</span>
</span></span><span class="line"><span class="cl"><span class="na">set cindent</span>
</span></span><span class="line"><span class="cl"><span class="na">set si</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>设置修改配置文件直接应用</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">autocmd BufWritePost $MYVIMRC source $MYVIMRC</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>配置调试<code>python</code>,<code>cpp</code>,<code>sh</code>：使用F5执行输出，默认删除编译的c++</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">set showcmd &#34;show the cmd before carry out on vim</span>
</span></span><span class="line"><span class="cl"><span class="na">map &lt;F5&gt; :call CompileRunGcc()&lt;CR&gt;</span>
</span></span><span class="line"><span class="cl"><span class="na">func! CompileRunGcc()</span>
</span></span><span class="line"><span class="cl">    <span class="na">exec &#34;w&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">if &amp;filetype</span> <span class="o">=</span><span class="s">= &#39;cpp&#39;
</span></span></span><span class="line"><span class="cl"><span class="s">        exec &#39;!g++ % -o %&lt;&#39;
</span></span></span><span class="line"><span class="cl"><span class="s">        exec &#39;!time ./%&lt;&#39;
</span></span></span><span class="line"><span class="cl"><span class="s">        exec &#39;!rm ./%&lt;&#39;
</span></span></span><span class="line"><span class="cl"><span class="s">    elseif &amp;filetype == &#39;python&#39;
</span></span></span><span class="line"><span class="cl"><span class="s">        exec &#39;!python %&#39;
</span></span></span><span class="line"><span class="cl"><span class="s">    elseif &amp;filetype == &#39;sh&#39;
</span></span></span><span class="line"><span class="cl"><span class="s">        :!time sh %
</span></span></span><span class="line"><span class="cl"><span class="s">    endif</span>
</span></span><span class="line"><span class="cl"><span class="na">endfunc&lt;Paste&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="na">&#34;running python in nvim</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34;nnoremap &lt;F5&gt; :echo system(&#39;python3 &#34;&#39; . expand(&#39;%&#39;) . &#39;&#34;&#39;)&lt;cr&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="na">&#34; running cpp in nvim</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; map &lt;F8&gt; :w &lt;CR&gt; :!g++ % -o %&lt; &amp;&amp; ./%&lt; &lt;CR&gt;</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; nnoremap &lt;silent&gt; &lt;F8&gt; :!clear;g++ % -o % &amp;&amp; ./%&lt; &lt;CR&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>支持中文编码：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">set encoding</span><span class="o">=</span><span class="s">utf-8</span>
</span></span><span class="line"><span class="cl"><span class="na">set termencoding</span><span class="o">=</span><span class="s">utf-8</span>
</span></span><span class="line"><span class="cl"><span class="na">set fileencodings</span><span class="o">=</span><span class="s">utf-8,ucs-bom,gb18030,gbk,gb2312,cp936</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>支持鼠标操作：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">set mouse</span><span class="o">=</span><span class="s">a</span>
</span></span><span class="line"><span class="cl"><span class="na">set selection</span><span class="o">=</span><span class="s">exclusive</span>
</span></span><span class="line"><span class="cl"><span class="na">set selectmode</span><span class="o">=</span><span class="s">mouse,key</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="folding-setting">Folding Setting</h3>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20211014210253777.png">
    <img alt="image-20211014210253777" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20211014210253777.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20211014210253777.png" style="display: block; margin: 0 auto;"
      alt="image-20211014210253777"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>THE RESULT AFTER SETTING WILL BE LIKE THIS</p>
<p>And the Folding can be ：<code>mark</code>,<code>indent</code>,<code>syntax</code></p>
<p>This is not the final version of folding setting, we will contiune complete it.</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">&#34; https://www.cnblogs.com/zlcxbb/p/6442092.html</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="na">set foldmethod</span><span class="o">=</span><span class="s">indent</span>
</span></span><span class="line"><span class="cl"><span class="na">set foldlevel</span><span class="o">=</span><span class="s">1 &#34;预设开始时不收起</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="na">autocmd FileType vim set foldmarker</span><span class="o">=</span><span class="s">{{{,}}}</span>
</span></span><span class="line"><span class="cl"><span class="na">autocmd FileType vim set foldmethod</span><span class="o">=</span><span class="s">marker</span>
</span></span><span class="line"><span class="cl"><span class="na">autocmd FileType vim set foldlevel</span><span class="o">=</span><span class="s">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="na">autocmd FileType python,cpp set foldmethod</span><span class="o">=</span><span class="s">indent</span>
</span></span><span class="line"><span class="cl"><span class="na">autocmd FileType python,cpp set foldlevel</span><span class="o">=</span><span class="s">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="na">&#34;autocmd FileType cpp set foldmethod</span><span class="o">=</span><span class="s">marker</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34;autocmd FileType cpp set foldmarker</span><span class="o">=</span><span class="s">{,}</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34;autocmd FileType cpp set foldlevel</span><span class="o">=</span><span class="s">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="na">&#34; let php_folding</span><span class="o">=</span><span class="s">1</span>
</span></span><span class="line"><span class="cl"><span class="na">set foldnestmax</span><span class="o">=</span><span class="s">3</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="color-and-themebasic">Color And Theme(basic)</h3>
<p><a href="https://vimcolorschemes.com/" target="_blank" rel="noopener">Trending vim color schemes | vimcolorschemes</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mkdir ~/.config/nvim/colors
</span></span><span class="line"><span class="cl"><span class="c1"># them we dowmload theme in this dir</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在<code>Plug</code>同级目录下创建<code>colors</code>文件夹，将对应的配色文件放到<code>colors</code>，<code>autoload</code>中，</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">set wildmenu</span>
</span></span><span class="line"><span class="cl"><span class="na">set background</span><span class="o">=</span><span class="s">dark</span>
</span></span><span class="line"><span class="cl"><span class="na">colorscheme NeoSolarized</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="na">highlight Visual cterm</span><span class="o">=</span><span class="s">NONE ctermbg=236 ctermfg=NONE guibg=Grey40</span>
</span></span><span class="line"><span class="cl"><span class="na">highlight LineNr cterm</span><span class="o">=</span><span class="s">none ctermfg=240 guifg=#2b506e guibg=#000000</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="na">&#34; 背景透明</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34;hi Normal ctermfg</span><span class="o">=</span><span class="s">252 ctermbg=none &#34;背景透明</span>
</span></span><span class="line"><span class="cl"><span class="na">autocmd vimenter * hi Normal guibg</span><span class="o">=</span><span class="s">NONE ctermbg=NONE &#34; transparent bg</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="na">“ 语法高亮，高亮当前行，当前列</span>
</span></span><span class="line"><span class="cl"><span class="na">syntax on</span>
</span></span><span class="line"><span class="cl"><span class="na">set cul &#34;highlight cursorline</span>
</span></span><span class="line"><span class="cl"><span class="na">set cuc</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="na">&#34; set termguicolors</span>
</span></span><span class="line"><span class="cl"><span class="na">set t_Co</span><span class="o">=</span><span class="s">256</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; 设置状态栏</span>
</span></span><span class="line"><span class="cl"><span class="na">set laststatus</span><span class="o">=</span><span class="s">2</span>
</span></span><span class="line"><span class="cl"><span class="na">set ruler</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="na">&#34; set themes</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; gruvbox</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; colorscheme gruvbox</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="na">”</span> <span class="o">=</span><span class="s">====================指定的主题设置</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; NeoSolarized</span>
</span></span><span class="line"><span class="cl"><span class="na">colorscheme NeoSolarized</span>
</span></span><span class="line"><span class="cl"><span class="na">let g:neosolarized_termtrans</span><span class="o">=</span><span class="s">1</span>
</span></span><span class="line"><span class="cl"><span class="na">runtime ./colors/NeoSolarized.vim</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="na">&#34; Onedark</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; https://github.com/joshdick/onedark.vim</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; we should change this in the airline setting</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; colorscheme onedark</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; let g:airline_theme</span> <span class="o">=</span> <span class="s">&#39;onedark&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="na">&#34; space-vim-dark</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; https://github.com/liuchengxu/space-vim-dark</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; colorscheme space-vim-dark</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; hi Comment cterm</span><span class="o">=</span><span class="s">italic</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; hi LineNr ctermbg</span><span class="o">=</span><span class="s">NONE guibg=NONE</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="na">&#34; one-half</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; https://github.com/sonph/onehalf/tree/master/vim</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; colorscheme onehalfdark</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="mapping-shortcut">Mapping Shortcut</h3>
<p>快捷键映射是配置自定义的核心内容，这一块会分享一些比较特别的映射。</p>
<p>Shortcut key mapping is the core content of configuration customization. This section will share some special mappings.</p>
<table>
  <thead>
      <tr>
          <th>快捷键配置</th>
          <th>修改位置和方法</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>插件的默认配置</td>
          <td><code>.config/nvim/plugins/NAME/PLUG.vim</code> <br />1. 修改对应的快捷键<br />2. 主配置文件中duplicate 对应的命令</td>
      </tr>
      <tr>
          <td>默认的配置文件</td>
          <td>在不同的命令下分别对应<br />1. 普通模式下的映射<br />2. 可视模式下的映射</td>
      </tr>
  </tbody>
</table>
<p>配置使用<code>&lt;Alt&gt;</code>进行<code>windows</code>的切换</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">&#34; https://vim.fandom.com/wiki/Switch_between_Vim_window_splits_easily</span>
</span></span><span class="line"><span class="cl"><span class="na">nmap &lt;silent&gt; &lt;A-Up&gt; :wincmd k&lt;CR&gt;</span>
</span></span><span class="line"><span class="cl"><span class="na">nmap &lt;silent&gt; &lt;A-Down&gt; :wincmd j&lt;CR&gt;</span>
</span></span><span class="line"><span class="cl"><span class="na">nmap &lt;silent&gt; &lt;A-Left&gt; :wincmd h&lt;CR&gt;</span>
</span></span><span class="line"><span class="cl"><span class="na">nmap &lt;silent&gt; &lt;A-Right&gt; :wincmd l&lt;CR&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>配置tab和shift tab来实现vscode中的行缩进配置</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">nmap &lt;tab&gt; V&gt;</span>
</span></span><span class="line"><span class="cl"><span class="na">nmap &lt;S-tab&gt; V&lt;</span>
</span></span><span class="line"><span class="cl"><span class="na">vmap &lt;tab&gt; Vg&gt;</span>
</span></span><span class="line"><span class="cl"><span class="na">vmap &lt;S-tab&gt; Vg&lt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>特殊命令：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">&#34; del the end space of line</span>
</span></span><span class="line"><span class="cl"><span class="na">nnoremap &lt;leader&gt;de :%s/\s\+$//&lt;cr&gt;:let @/</span><span class="o">=</span><span class="s">&#39;&#39;&lt;CR&gt;</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; edit the nvim config file</span>
</span></span><span class="line"><span class="cl"><span class="na">nnoremap &lt;leader&gt;ev :vsp $MYVIMRC&lt;CR&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>复制粘贴全选：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">map &lt;C-A&gt;ggVGY</span>
</span></span><span class="line"><span class="cl"><span class="na">map! &lt;C-A&gt; &lt;Esc&gt;ggVGY</span>
</span></span><span class="line"><span class="cl"><span class="na">map &lt;F12&gt; gg</span><span class="o">=</span><span class="s">G</span>
</span></span><span class="line"><span class="cl"><span class="na">” 选中状态下ctrl+c复制</span>
</span></span><span class="line"><span class="cl"><span class="na">vmap &lt;C-c&gt; &#34;+y</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="plugs">Plugs</h2>
<p>插件是个性化配置的另一个核心点；Plugs is another core of personalized configuration</p>
<p>使用插件来支持语法，外观，补全，文件管理 ；Use plugins to support syntax, appearance, completion, and file management ；</p>
<ul>
<li>安装插件的时候，如果遇到一些安装失败的时候，我们可以通过以下的命令来获取对应的详细信息<code>:messages</code></li>
</ul>
<h3 id="vim-plug">VIM-PLUG</h3>
<p><a href="https://github.com/junegunn/vim-plug" target="_blank" rel="noopener">junegunn/vim-plug: Minimalist Vim Plugin Manager (github.com)</a>
</p>
<p>你只需打开终端并运行以下命令：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -fLo ~/.vim/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>Neovim 用户可以使用以下命令安装 Vim-plug：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -fLo ~/.config/nvim/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>安装完插件管理器，我们可以在配置文件中通过一下的操作来安装插件：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="c1"># 设置存放插件的地址</span>
</span></span><span class="line"><span class="cl"><span class="na">call plug#begin(&#39;~/.config/nvim/plugged&#39;)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 添加我们需要的插件</span>
</span></span><span class="line"><span class="cl"><span class="na">call plug#end()</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>常用的一些命令：</p>
<table>
  <thead>
      <tr>
          <th>Command</th>
          <th>Desc</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>PlugInstall</td>
          <td>Install Package</td>
      </tr>
      <tr>
          <td>PlugUpdate</td>
          <td>Update those packages</td>
      </tr>
      <tr>
          <td>PlugStatus</td>
          <td>Show The Status of all the package</td>
      </tr>
      <tr>
          <td>PlugClean</td>
          <td>Clean the error Plug or del those Plug not Define any more</td>
      </tr>
      <tr>
          <td>PlugUpgrade</td>
          <td>Update Vim-Plug itself</td>
      </tr>
  </tbody>
</table>
<p>常用的一些命令优化下载速度更换源：</p>
<p><a href="https://blog.csdn.net/liudglink/article/details/118483261" target="_blank" rel="noopener">加速vim-plug安装</a>
，<a href="https://tinker.run/article/13" target="_blank" rel="noopener">cnpm，github</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="c1"># 在调用call plug之前设置下载的源地址</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 这里实际上可以参考各种镜像站去写</span>
</span></span><span class="line"><span class="cl"><span class="na">let g:plug_url_format</span><span class="o">=</span><span class="s">&#39;https://git::@hub.fastgit.org/%s.git&#39;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>或者我们借助Windows主机的代理服务器来对Github进行加速，如果存在稳定的代理的话，这个方式可能是更优的一个
参考[[Envs/Windows.md]]中的Proxy</p>
<h3 id="langs-support">Langs Support</h3>
<p>这一部分介绍各种语言的支持LSP，以及对应的配置操作。</p>
<h2 id="appendix">Appendix</h2>
<h3 id="add-header-for-langs">Add Header for Langs</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">“ head can write like this</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34; 新建.c,.h,.sh,.java文件，自动插入文件头</span>
</span></span><span class="line"><span class="cl"><span class="na">autocmd BufNewFile *.cpp,*.[ch],*.sh,*.py exec &#34;:call SetTitle()&#34;</span>
</span></span><span class="line"><span class="cl"><span class="na">&#34;&#34;定义函数SetTitle，自动插入文件头</span>
</span></span><span class="line"><span class="cl"><span class="na">func SetTitle()</span>
</span></span><span class="line"><span class="cl">    <span class="na">&#34;如果文件类型为.sh文件</span>
</span></span><span class="line"><span class="cl">    <span class="na">if &amp;filetype</span> <span class="o">=</span><span class="s">= &#39;sh&#39;
</span></span></span><span class="line"><span class="cl"><span class="s">        call setline(1, &#34;##########################################################################&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;), &#34;# File Name: &#34;.expand(&#34;%&#34;))
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+1, &#34;# Author: AikenHong &#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+2, &#34;# mail: h.aiken.970@gmail.com&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+3, &#34;# Created Time: &#34;.strftime(&#34;%c&#34;))
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+4, &#34;&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">    endif
</span></span></span><span class="line"><span class="cl"><span class="s">    if &amp;filetype == &#39;cpp&#39;
</span></span></span><span class="line"><span class="cl"><span class="s">        call setline(1, &#34;/*&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;), &#34;# File Name: &#34;.expand(&#34;%&#34;))
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+1, &#34;# Author: AikenHong &#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+2, &#34;# mail: h.aiken.970@gmail.com&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+3, &#34;# Created Time: &#34;.strftime(&#34;%c&#34;))
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+4, &#34; */&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+5, &#34; &#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+6, &#34;#include &lt;iostream&gt;&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+7, &#34;#include &lt;algorithm&gt;&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+8, &#34;#include &lt;vector&gt;&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+9, &#34;#include &lt;stack&gt;&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+10, &#34;#include &lt;queue&gt;&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+11, &#34;#include &lt;list&gt;&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+12, &#34;#include &lt;map&gt;&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+13, &#34;#include &lt;cmath&gt;&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+14, &#34;#include &lt;set&gt;&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+15, &#34;&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+16, &#34;using namespace std;&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+17, &#34;&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+18, &#34;int main()&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+19, &#34;{&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+20, &#34;    &#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+21, &#34;    &#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+22, &#34;    return 0;&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+23, &#34;}&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">    endif
</span></span></span><span class="line"><span class="cl"><span class="s">    if &amp;filetype == &#39;python&#39;
</span></span></span><span class="line"><span class="cl"><span class="s">        call setline(1, &#34;\&#34;\&#34;\&#34;&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;), &#34;# File Name: &#34;.expand(&#34;%&#34;))
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+1, &#34;# Author: AikenHong &#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+2, &#34;# mail: h.aiken.970@gmail.com&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+3, &#34;# Created Time: &#34;.strftime(&#34;%c&#34;))
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+4, &#34;\&#34;\&#34;\&#34;&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">        call append(line(&#34;.&#34;)+5, &#34;&#34;)
</span></span></span><span class="line"><span class="cl"><span class="s">    endif
</span></span></span><span class="line"><span class="cl"><span class="s">    &#34;新建文件后，自动定位到文件末尾
</span></span></span><span class="line"><span class="cl"><span class="s">    autocmd BufNewFile * normal G</span>
</span></span><span class="line"><span class="cl"><span class="na">endfunction</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="dependency">Dependency</h3>
<p>This Session I’ll intrduce some dependency for those PLUGs and the env</p>
<h3 id="reference">Reference</h3>
<ul>
<li><a href="https://github.com/Yggdroot/LeaderF" target="_blank" rel="noopener">Yggdroot/LeaderF</a>
 : basic config and keyshort setting</li>
<li><a href="https://github.com/liuchengxu/vim-which-key#special-keys" target="_blank" rel="noopener">liuchengxu/vim-which-key</a>
</li>
<li><a href="https://www.chrisatmachine.com/Neovim/15-which-key/" target="_blank" rel="noopener">Config your which key</a>
</li>
<li><a href="https://github.com/vim-airline/vim-airline/wiki/Screenshots" target="_blank" rel="noopener"> vim-airline-themes</a>
</li>
<li><a href="https://vimawesome.com/" target="_blank" rel="noopener">Vim Awesome</a>
</li>
<li><a href="https://github.com/plasticboy/vim-markdown" target="_blank" rel="noopener">plasticboy/vim-markdown</a>
</li>
<li><a href="https://www.cnblogs.com/cniwoq/p/13272746.html" target="_blank" rel="noopener">Neovim+Coc.nvim配置 目前个人最舒服终端编辑环境(Python&amp;C++) - zprhhs - 博客园 (cnblogs.com)</a>
</li>
<li><a href="https://gitee.com/springhan/nvim/blob/master/init.vim" target="_blank" rel="noopener">init.vim · SpringHan/nvim - Gitee.com</a>
</li>
<li><a href="https://stackoverflow.com/questions/18948491/running-python-code-in-vim" target="_blank" rel="noopener">Python</a>
；</li>
<li><a href="https://stackoverflow.com/questions/2627886/how-do-i-run-a-c-program-from-vim" target="_blank" rel="noopener">C</a>
：Using g++ instead of gcc will support C++</li>
</ul>
<h3 id="configuration-file">Configuration File</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="coc安装注意事项">COC安装注意事项</h3>
<p>安装npm，node</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm install -g neovim</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>build/index.js not found, please install dependencies and compile coc.nvim by: yarn insta</p>
<p>切换到coc目录，yarn install，</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">cd</span> ~/.config/nvim/plugged/coc.nvim
</span></span><span class="line"><span class="cl">yarn install
</span></span><span class="line"><span class="cl">yarn build</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>安装clang：</p>
<p><a href="https://clangd.llvm.org/installation.html" target="_blank" rel="noopener">Getting started (llvm.org)</a>
</p>
<h3 id="airline">Airline</h3>
<p>Install Powerline Font <a href="https://github.com/powerline/fonts" target="_blank" rel="noopener">powerline/fonts: Patched fonts for Powerline users. (github.com)</a>
</p>
<h3 id="tagbar">Tagbar</h3>
<p>该安装依赖于ctags为了支持Markdown情况下的Tagbar,这里推荐安装Universal Ctags</p>
<ol>
<li>
<p>使用镜像站clone</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">cd</span> .install/
</span></span><span class="line"><span class="cl">sudo git clone https://github.com.cnpmjs.org/universal-ctags/ctags.git
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> ctags</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>安装前置依赖</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt-get install make <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  autoconf <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  ppkg-config
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">sudo apt install <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    gcc make <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    pkg-config autoconf automake <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    python3-docutils <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    libseccomp-dev <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    libjansson-dev <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    libyaml-dev <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    libxml2-dev</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>在<code>ctags</code>目录下安装</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">./autogen.sh
</span></span><span class="line"><span class="cl">./configure --prefix<span class="o">=</span>/where/you/want <span class="c1"># defaults to /usr/local</span>
</span></span><span class="line"><span class="cl">make
</span></span><span class="line"><span class="cl">sudo make install</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>验证安装成功与否</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ctags
</span></span><span class="line"><span class="cl"><span class="c1"># sueecess will output</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ctags: No files specified. Try &#34;ctags --help&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>support <a href="https://github.com/preservim/tagbar/wiki#markdown" target="_blank" rel="noopener">markdown</a>
</p>
<p>Add those into vimrc</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">let g:tagbar_type_markdown</span> <span class="o">=</span> <span class="s">{
</span></span></span><span class="line"><span class="cl"><span class="s">  \ &#39;ctagstype&#39;  : &#39;markdown&#39;,
</span></span></span><span class="line"><span class="cl"><span class="s">  \ &#39;kinds&#39;      : [
</span></span></span><span class="line"><span class="cl"><span class="s">    \ &#39;c:chapter:0:1&#39;,
</span></span></span><span class="line"><span class="cl"><span class="s">    \ &#39;s:section:0:1&#39;,
</span></span></span><span class="line"><span class="cl"><span class="s">    \ &#39;S:subsection:0:1&#39;,
</span></span></span><span class="line"><span class="cl"><span class="s">    \ &#39;t:subsubsection:0:1&#39;,
</span></span></span><span class="line"><span class="cl"><span class="s">    \ &#39;T:l4subsection:0:1&#39;,
</span></span></span><span class="line"><span class="cl"><span class="s">    \ &#39;u:l5subsection:0:1&#39;,
</span></span></span><span class="line"><span class="cl"><span class="s">  \ ],
</span></span></span><span class="line"><span class="cl"><span class="s">  \ &#39;sro&#39;            : &#39;&#34;&#34;&#39;,
</span></span></span><span class="line"><span class="cl"><span class="s">  \ &#39;kind2scope&#39; : {
</span></span></span><span class="line"><span class="cl"><span class="s">    \ &#39;c&#39; : &#39;chapter&#39;,
</span></span></span><span class="line"><span class="cl"><span class="s">    \ &#39;s&#39; : &#39;section&#39;,
</span></span></span><span class="line"><span class="cl"><span class="s">    \ &#39;S&#39; : &#39;subsection&#39;,
</span></span></span><span class="line"><span class="cl"><span class="s">    \ &#39;t&#39; : &#39;subsubsection&#39;,
</span></span></span><span class="line"><span class="cl"><span class="s">    \ &#39;T&#39; : &#39;l4subsection&#39;,
</span></span></span><span class="line"><span class="cl"><span class="s">  \ },
</span></span></span><span class="line"><span class="cl"><span class="s">  \ &#39;scope2kind&#39; : {
</span></span></span><span class="line"><span class="cl"><span class="s">    \ &#39;chapter&#39; : &#39;c&#39;,
</span></span></span><span class="line"><span class="cl"><span class="s">    \ &#39;section&#39; : &#39;s&#39;,
</span></span></span><span class="line"><span class="cl"><span class="s">    \ &#39;subsection&#39; : &#39;S&#39;,
</span></span></span><span class="line"><span class="cl"><span class="s">    \ &#39;subsubsection&#39; : &#39;t&#39;,
</span></span></span><span class="line"><span class="cl"><span class="s">    \ &#39;l4subsection&#39; : &#39;T&#39;,
</span></span></span><span class="line"><span class="cl"><span class="s">  \ },</span>
</span></span><span class="line"><span class="cl"><span class="na">\ }</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
</ol>
<h3 id="startify-起始页设置">Startify 起始页设置</h3>
<p><a href="https://codeyarns.com/tech/2013-07-12-how-to-create-ascii-art-of-text-using-figlet.html" target="_blank" rel="noopener">Code Yarns – How to create ASCII art of text using FIGlet</a>
</p>
<p><a href="https://ricostacruz.com/til/project-switcher-using-startify" target="_blank" rel="noopener">Vim project switcher using Startify (ricostacruz.com)</a>
</p>
<h3 id="improve-npm-download">Improve NPM download</h3>
<p><a href="https://blog.csdn.net/weixin_46351593/article/details/112359906" target="_blank" rel="noopener">Download Npm Improve</a>
</p>
<p>临时设置：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm --registry https://registry.npm.taobao.org install express</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>全局使用：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm config <span class="nb">set</span> registry https://registry.npm.taobao.org</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>验证配置是否成功:</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm config get registry</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>通过cnpm使用：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm install -g cnpm --registry<span class="o">=</span>https://registry.npm.taobao.org</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="vim中执行程序">Vim中执行程序</h3>
<h3 id="markdown-preview-wsl">Markdown Preview WSL</h3>
<p>在WSL中无法调出preview的问题，运行时使用<code>message</code>查看err，若为&rsquo;Cannot find module &rsquo;tslib&rsquo;':</p>
<pre><code>到插件目录执行`yarn install`或者`npm install`
</code></pre>
<h2 id="split-windwos-窗口切分">Split Windwos 窗口切分</h2>
<p>this part is about windows split which is like tmux.
vim的窗口切分命令,在命令行的模式下执行</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">:vsp filepath/filename
</span></span><span class="line"><span class="cl"><span class="c1"># 垂直切分屏幕</span>
</span></span><span class="line"><span class="cl">:sp filepath/filename
</span></span><span class="line"><span class="cl"><span class="c1"># 横向切分屏幕</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>窗口,缓冲区切换快捷键</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>ini</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="c1"># cursor change in diff windows</span>
</span></span><span class="line"><span class="cl"><span class="na">ctrl + &lt;- -&gt;</span>
</span></span><span class="line"><span class="cl"><span class="na">ctrl + w + direction</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># change buffer in diff tabs</span>
</span></span><span class="line"><span class="cl"><span class="na">alt + &lt;- -&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="vim-folding-折叠">Vim Folding 折叠</h2>
<p><a href="https://www.cnblogs.com/zlcxbb/p/6442092.html" target="_blank" rel="noopener">vim折叠快捷键 </a>
</p>
<h2 id="vim-grammer-特殊用法">Vim Grammer 特殊用法</h2>
<p>Using Vim KEYSHORT like write an article with special grammar.
In the way, there&rsquo;ll be some interesting usage.
这里有一些有趣的用法，通过vim的语法可以列出来</p>
<h3 id="voice-语态">Voice 语态</h3>
<p>动词：r replace, d delete, y yank, f find, v visual
介词: i in, a around, t to, f forward
名词: w word, p paragraph, t tag, s sentence</p>
]]></content:encoded>
    </item>
    <item>
      <title>Vim Configuration 01 vim的无插件基础设置</title>
      <link>https://aikenh.cn/posts/vimconfigdf/</link>
      <pubDate>Thu, 07 Oct 2021 15:00:42 +0000</pubDate>
      <guid>https://aikenh.cn/posts/vimconfigdf/</guid>
      <description>deploy vim</description>
      <content:encoded><![CDATA[<blockquote>
<p>该配置笔记于 20230521 重新整理。默认的 Vimrc 位置为 <code>/usr/share/vim/vimrc</code>，也可以在 vim 界面使用 <code>:echo $MYVIMRC</code> 查看当前的配置文件，默认使用的配置文件地址为 <code>~/.vimrc</code></p>
</blockquote>
<p>参考文献地址：<a href="https://dougblack.io/words/a-good-vimrc.html" target="_blank" rel="noopener">Good VimRC</a>
 | <a href="https://segmentfault.com/a/1190000021029480" target="_blank" rel="noopener">Backspace</a>
 | <a href="https://zhuanlan.zhihu.com/p/98360630" target="_blank" rel="noopener">AutoCmd</a>
 | <a href="https://www.ruanyifeng.com/blog/2018/09/vimrc.html" target="_blank" rel="noopener">VIM配置入门</a>

配置文件地址：<a href="https://github.com/AikenH/aikenh-dotfile/tree/main/vim-dot" target="_blank" rel="noopener">AikenDotfile</a>
，本文这里只介绍部分配置，一些过于常见的配置等等这里就不再介绍，在 dotfile 中对每行配置均有的细致的注释。</p>
<p>基于 VimScript） 该 blog 主要记录基础 vim 的配置文件编写，旨在使用基础 vim 的时候也能有一个较好的代码编辑体验，同时提供部分 keymap 集成一些简单的功能，方便文档编写时候的格式转换等。这个配置文件在后续配置 nvim 的时候部分配置也会沿用。</p>
<h2 id="vim-的基础配置">Vim 的基础配置</h2>
<p>自动检测文件修改，以及对多个文件的 workspace 自动切换</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>vim</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vim" data-lang="vim"><span class="line"><span class="cl"><span class="c">&#34; &gt;&gt;0-1 state detection.</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">autoread</span> <span class="c">&#34; when file change outside, we will know</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">autochdir</span> <span class="c">&#34; change workspace when we swtich file, when we open multi-file in one session.</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="鼠标和剪切板功能">鼠标和剪切板功能</h3>
<p>设置 vim 对鼠标的支持，支持鼠标选择等</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>vim</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vim" data-lang="vim"><span class="line"><span class="cl"><span class="c">&#34; reference the web get the best setting and use it always</span>
</span></span><span class="line"><span class="cl"><span class="c">&#34; suppose the mouse operation</span>
</span></span><span class="line"><span class="cl"><span class="c">&#34; but this function not work well in the weterm, we disable this part for work.</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">mouse</span><span class="p">=</span><span class="nx">a</span>
</span></span><span class="line"><span class="cl"><span class="c">&#34;set selection=exclusive</span>
</span></span><span class="line"><span class="cl"><span class="c">&#34;set selectmode=mouse,key</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>设置和系统同步的剪切板，WSL 下的剪切板设置可以参考下面文章 <a href="https://github.com/microsoft/WSL/issues/4440" target="_blank" rel="noopener">WSL2 clipboard not shared between Linux and Windows</a>
 || <a href="https://www.reddit.com/r/bashonubuntuonwindows/comments/be2q3l/comment/el2vx7u/?utm_source#" target="_blank" rel="noopener">Reddit - Dive into anything</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>vim</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vim" data-lang="vim"><span class="line"><span class="cl"><span class="c">&#34; set the clipboard</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">clipboard</span><span class="p">+=</span><span class="nx">unnamed</span>
</span></span><span class="line"><span class="cl"><span class="c">
</span></span></span><span class="line"><span class="cl"><span class="c">&#34; WSL yank support</span>
</span></span><span class="line"><span class="cl"><span class="k">let</span> <span class="nx">s</span>:<span class="nx">clip</span> <span class="p">=</span> <span class="s1">&#39;/mnt/c/WINDOWS/system32/clip.exe&#39;</span>  <span class="c">&#34; change this path according to your mount point</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="nx">executable</span><span class="p">(</span><span class="nx">s</span>:<span class="nx">clip</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nx">augroup</span> <span class="nx">WSLYank</span>
</span></span><span class="line"><span class="cl">        <span class="k">autocmd</span><span class="p">!</span>
</span></span><span class="line"><span class="cl">        <span class="k">autocmd</span> <span class="nx">TextYankPost</span> * <span class="k">if</span> <span class="nx">v</span>:<span class="nx">event</span>.<span class="nx">operator</span> <span class="p">==</span># <span class="s1">&#39;y&#39;</span> <span class="p">|</span> <span class="nx">call</span> <span class="nx">system</span><span class="p">(</span><span class="nx">s</span>:<span class="nx">clip</span><span class="p">,</span> @<span class="m">0</span><span class="p">)</span> <span class="p">|</span> <span class="k">endif</span>
</span></span><span class="line"><span class="cl">    <span class="nx">augroup</span> <span class="nx">END</span>
</span></span><span class="line"><span class="cl"><span class="k">endif</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="设置撤销历史记录">设置撤销历史记录</h3>
<blockquote>
<p>多次编辑同一个文件的时候保持 Undo 的历史记录，便于对同一个文件进行编辑。</p>
</blockquote>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>vim</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vim" data-lang="vim"><span class="line"><span class="cl"><span class="c">&#34; &gt;&gt;0-2 keep file history</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">undofile</span> <span class="c">&#34; keep the undo history in file.</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">undodir</span><span class="p">=~</span><span class="sr">/.vim/</span>.<span class="nx">undo</span><span class="sr">//</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">history</span><span class="p">=</span><span class="m">1000</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>通过上述命令启用 undofile 的选项，并设置存储目录，这里需要注意的是，<strong>存储目录需要手动创建</strong>，undo 的历史记录才能生效。</p>
<h3 id="搜索选项">搜索选项</h3>
<p>搜索部分主要有以下的几个事：显示匹配的括号，逐字搜索，搜索高亮，忽略大小写</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>vim</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vim" data-lang="vim"><span class="line"><span class="cl"><span class="c">&#34; &gt;&gt;1-3 Search Setting</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">showmatch</span> <span class="c">&#34; highlight match parentheses</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">incsearch</span> <span class="c">&#34; search as characters are entered</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">hlsearch</span> <span class="c">&#34; highlight the search result.</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">ignorecase</span> <span class="c">&#34; ignore cases when searching</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>其中需要注意的是，vim 中的搜索高亮不会自动关闭，因此我们需要设置快捷键映射来关闭搜索的高亮。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>vim</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vim" data-lang="vim"><span class="line"><span class="cl"><span class="nx">nnoremap</span> <span class="p">&lt;</span><span class="nx">leader</span><span class="p">&gt;</span><span class="nx">ss</span> :<span class="nx">nohlsearch</span><span class="p">&lt;</span><span class="nx">CR</span><span class="p">&gt;</span> <span class="c">&#34; turn off the highlight, bcus it will not auto close.</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="其他设置">其他设置</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>vim</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vim" data-lang="vim"><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">backspace</span><span class="p">=</span><span class="nx">indent</span><span class="p">,</span><span class="nx">eol</span><span class="p">,</span><span class="nx">start</span> <span class="c">&#34; help to del special character.(or =2)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="基本用户界面设置">基本用户界面设置</h2>
<p>设置滚动行和上下的间距：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>vim</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vim" data-lang="vim"><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">scrolloff</span><span class="p">=</span><span class="m">10</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>设置折行及折行不破坏单词完整性：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>vim</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vim" data-lang="vim"><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">wrap</span> <span class="c">&#34; wrap line and if line is too long</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">linebreak</span> <span class="c">&#34; Line breaks do not break the word.</span>
</span></span><span class="line"><span class="cl"><span class="c">&#34; set textwidth=80 &#34; how many chacter in oneline</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="状态栏设置">状态栏设置</h3>
<p>首先设置命令窗口的大小，并使得状态栏仅在多文件窗口时打开，便于区分不同文件</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>vim</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vim" data-lang="vim"><span class="line"><span class="cl"><span class="c">&#34; &gt;&gt;2-3 Status Line Setting</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">cmdheight</span><span class="p">=</span><span class="m">2</span> <span class="c">&#34; set the cmd line height</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">laststatus</span><span class="p">=</span><span class="m">1</span> <span class="c">&#34; enable:2 only in multi windows:1 off:0</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">ruler</span> <span class="c">&#34; show row,col of cursor in status line.</span>
</span></span><span class="line"><span class="cl"><span class="c">
</span></span></span><span class="line"><span class="cl"><span class="c">&#34; reference : https://blog.csdn.net/strategycn/article/details/7620261</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">statusline</span><span class="p">=</span>%<span class="nx">F</span>%<span class="nx">m</span>%<span class="nx">r</span>%<span class="nx">h</span>%<span class="nx">w</span>\ [<span class="nx">FORMAT</span><span class="p">=</span>%{&amp;<span class="nx">ff</span>}]\ [<span class="nx">TYPE</span><span class="p">=</span>%<span class="nx">Y</span>]\ [<span class="nx">POS</span><span class="p">=</span>%<span class="m">04</span>l<span class="p">,</span>%<span class="m">04</span>v][%<span class="nx">p</span>%%]\ [<span class="nx">LEN</span><span class="p">=</span>%<span class="nx">L</span>]\ [<span class="nx">TIME</span><span class="p">=</span>%{<span class="nx">strftime</span><span class="p">(</span><span class="s1">&#39;%c&#39;</span><span class="p">)</span>}]</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>设置 VIm 的 CMD 指令显示状态以及补全办法：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>vim</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vim" data-lang="vim"><span class="line"><span class="cl"><span class="c">&#34; &gt;&gt;2-4 Command hint.</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">showcmd</span> <span class="c">&#34; show the command we just type in. like 2d</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">showmode</span> <span class="c">&#34; show insert or command mode now (seems like not working)</span>
</span></span><span class="line"><span class="cl"><span class="c">
</span></span></span><span class="line"><span class="cl"><span class="c">&#34; &gt;&gt;2-5 show Bottom CMD Menu</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">wildmenu</span> <span class="c">&#34; show completion list.</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="光标位置记录">光标位置记录</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>vim</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vim" data-lang="vim"><span class="line"><span class="cl"><span class="c">&#34; &gt;&gt;2-7 return to last edit pos when open same files.</span>
</span></span><span class="line"><span class="cl"><span class="k">autocmd</span> <span class="nx">BufReadPost</span> *
</span></span><span class="line"><span class="cl">    \ <span class="k">if</span> <span class="nx">line</span><span class="p">(</span><span class="s2">&#34;&#39;\&#34;&#34;</span><span class="p">)</span> <span class="p">&gt;</span> <span class="m">0</span> &amp;&amp; <span class="nx">line</span><span class="p">(</span><span class="s2">&#34;&#39;\&#34;&#34;</span><span class="p">)</span> <span class="p">&lt;=</span> <span class="nx">line</span><span class="p">(</span><span class="s2">&#34;$&#34;</span><span class="p">)</span> <span class="p">|</span>
</span></span><span class="line"><span class="cl">    \   <span class="nx">exe</span> <span class="s2">&#34;normal! g`\&#34;&#34;</span> <span class="p">|</span>
</span></span><span class="line"><span class="cl">    \ <span class="k">endif</span>
</span></span><span class="line"><span class="cl"><span class="c">&#34; Remember info about open buffers on close</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">viminfo</span>^<span class="p">=</span>%</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="缩进方法和折叠">缩进方法和折叠</h2>
<blockquote>
<p>这里只以 Python 为例介绍默认的 indent 方案，同时 folder 这里只介绍 marker 方法，用 <code>{{{}}}</code> 来进行折叠，不同文件的 indent 方案用 filetype 和 autocmd 实现，具体参见配置文件中的 Part8.</p>
</blockquote>
<h3 id="缩进">缩进</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>vim</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vim" data-lang="vim"><span class="line"><span class="cl"><span class="c">&#34; &gt;&gt;3.1 Indent (c-style)</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">ai</span> <span class="c">&#34;autoindent, keep same indent with prev line.</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">si</span> <span class="c">&#34;smartindent, add {, # special situation of ai. (for c or java)</span>
</span></span><span class="line"><span class="cl"><span class="c">
</span></span></span><span class="line"><span class="cl"><span class="c">&#34; &gt;&gt;3.2 Tab(better using autocmd)</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">tabstop</span><span class="p">=</span><span class="m">4</span> <span class="c">&#34;tab==&lt;n&gt; space</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">softtabstop</span><span class="p">=</span><span class="m">4</span> <span class="c">&#34;when we type in tab == &lt;n&gt; space</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">shiftwidth</span><span class="p">=</span><span class="m">4</span> <span class="c">&#34;the auto indet(when change line or using &gt; or &lt; ) will be &lt;n&gt; better keep it same with tab.</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">smarttab</span> <span class="c">&#34;will change &lt;n&gt; basis on others in this file.</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">expandtab</span> <span class="c">&#34;make all tab as space</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这里的 <code>&lt;n&gt;</code> 指的是空格的个数，具体的设置和注释如上，后续基于不同的文件类型进行配置的需要打开如下的内容：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>vim</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vim" data-lang="vim"><span class="line"><span class="cl"><span class="c">&#34; &gt;&gt;3.3 specific indent file.</span>
</span></span><span class="line"><span class="cl"><span class="c">&#34; load filetype-specific indent files.</span>
</span></span><span class="line"><span class="cl"><span class="c">&#34; *.py will load ~/.vim/indent/python.vim file</span>
</span></span><span class="line"><span class="cl"><span class="k">filetype</span> <span class="nx">on</span>
</span></span><span class="line"><span class="cl"><span class="k">filetype</span> <span class="nx">plugin</span> <span class="nx">on</span>
</span></span><span class="line"><span class="cl"><span class="k">filetype</span> <span class="nx">indent</span> <span class="nx">on</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>其他内容参见 dotfile，使用 autocmd 对不同文件的缩进进行区分设置。</p>
<h3 id="折叠">折叠</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>vim</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vim" data-lang="vim"><span class="line"><span class="cl"><span class="c">&#34; -----------------------6.Folder{{{-----------------------------</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">foldenable</span> <span class="c">&#34; enable fold function</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">foldlevelstart</span><span class="p">=</span><span class="m">10</span> <span class="c">&#34; fold level at start. 0: all be closed; 99: always open.</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">foldnestmax</span><span class="p">=</span><span class="m">10</span> <span class="c">&#34; 10 nested fold max</span>
</span></span><span class="line"><span class="cl"><span class="k">set</span> <span class="nx">foldmethod</span><span class="p">=</span><span class="nx">marker</span> <span class="c">&#34; could be indent. mark should use {{{}}}</span>
</span></span><span class="line"><span class="cl"><span class="c">&#34;try help foldmethod</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>将折叠全开后的效果如下：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230524164856.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230524164856.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230524164856.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="快捷键和函数">快捷键和函数</h2>
<blockquote>
<p>快捷键和函数的数量较多，这里不详细说，具体查看 dotfile，这里简要说明以下主要实现了哪些 KeyMap。</p>
</blockquote>
<p>这里通过快捷键和函数实现了如下的一些功能。</p>
<ol>
<li>用 TAB 和 SHIFT-TAB 调整缩进</li>
<li>Toggle Wrap、Spell、Number、Paste</li>
<li>快捷编辑配置文件</li>
<li>Windows、Tab 切换</li>
<li>快捷注释</li>
<li>Tailing 和 Retab</li>
<li>编译和执行当前代码文件</li>
<li>自动添加指定的文件头（如 blog 的 meta 文件）</li>
</ol>
<p>由于篇幅限制就不再赘述。</p>
<h2 id="自动注释">自动注释</h2>
<p>感谢大神 <a href="https://github.com/KarimElghamry/vim-auto-comment" target="_blank" rel="noopener">KarimElghamry</a>
 提供的方案，可以直接将其代码拷贝到自己的 vmrc 中来实现行注释和块注释，也可以很轻易的添加不同后缀的处理方式。</p>
<h2 id="fi">FI</h2>
<p>该版本的 Vimrc 应该是个人的最终版本了，如果有其他的点子和需求的话，欢迎到评论区讨论，如果有更新的话也会在这个 dotfile 上更新。</p>
]]></content:encoded>
    </item>
    <item>
      <title>StyleGAN</title>
      <link>https://aikenh.cn/posts/stylegan/</link>
      <pubDate>Sun, 03 Oct 2021 13:16:40 +0000</pubDate>
      <guid>https://aikenh.cn/posts/stylegan/</guid>
      <description>&lt;h1 id=&#34;stylegan-v1&#34;&gt;StyleGAN V1&lt;/h1&gt;
&lt;p&gt;@AikenHong 2020 10.8&lt;/p&gt;
&lt;p&gt;《A Style-Based Generator Architecture for Generative Adversarial Networks》&lt;/p&gt;
&lt;h2 id=&#34;related-work&#34;&gt;Related Work：&lt;/h2&gt;
&lt;p&gt;继承的文献工作： ProGAN
参考解读：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.csdn.net/a312863063/article/details/88795147&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;《其中子链接值得一看》&lt;/a&gt;
（包括源码解析啥的）（甚至还有GAN的笔记）&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.gwylab.com/pdf/Note_StyleGAN.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;《StyleGan源码解析和拓展应用》&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://cuijiahua.com/blog/2020/07/dl-22.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;《秃头生成器1》&lt;/a&gt;
&lt;a href=&#34;https://cloud.tencent.com/developer/article/1658228&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;《秃头生成器2》 &lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://medium.com/swlh/hairstyle-transfer-semantic-editing-gan-latent-code-b3a6ccf91e82&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;NO.3&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Contribution（Problem）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;解纠缠：Mapping Network&lt;/li&gt;
&lt;li&gt;Noise Generator&lt;/li&gt;
&lt;li&gt;AdaIN before all conv&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;structure&#34;&gt;Structure：&lt;/h2&gt;
&lt;p&gt;
&lt;div class=&#34;post-img-view&#34;&gt;
  &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930135941.png&#34;&gt;
    &lt;img alt=&#34;image-20210930135938114&#34; loading=&#34;lazy&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930135941.png&#34;class=&#34;responsive-image&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930135941.png&#34; style=&#34;display: block; margin: 0 auto;&#34;
      alt=&#34;image-20210930135938114&#34;  /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;script&gt;
  document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
      var images = document.querySelectorAll(&#34;.responsive-image&#34;);
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + &#34;px&#34;;
      });
  });
&lt;/script&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;div class=&#34;post-img-view&#34;&gt;
  &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930161259.png&#34;&gt;
    &lt;img alt=&#34;image-20210930161258031&#34; loading=&#34;lazy&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930161259.png&#34;class=&#34;responsive-image&#34; src=&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930161259.png&#34; style=&#34;display: block; margin: 0 auto;&#34;
      alt=&#34;image-20210930161258031&#34;  /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;script&gt;
  document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
      var images = document.querySelectorAll(&#34;.responsive-image&#34;);
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + &#34;px&#34;;
      });
  });
&lt;/script&gt;
&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h1 id="stylegan-v1">StyleGAN V1</h1>
<p>@AikenHong 2020 10.8</p>
<p>《A Style-Based Generator Architecture for Generative Adversarial Networks》</p>
<h2 id="related-work">Related Work：</h2>
<p>继承的文献工作： ProGAN
参考解读：</p>
<ul>
<li><a href="https://blog.csdn.net/a312863063/article/details/88795147" target="_blank" rel="noopener">《其中子链接值得一看》</a>
（包括源码解析啥的）（甚至还有GAN的笔记）</li>
<li><a href="http://www.gwylab.com/pdf/Note_StyleGAN.pdf" target="_blank" rel="noopener">《StyleGan源码解析和拓展应用》</a>
</li>
<li><a href="https://cuijiahua.com/blog/2020/07/dl-22.html" target="_blank" rel="noopener">《秃头生成器1》</a>
<a href="https://cloud.tencent.com/developer/article/1658228" target="_blank" rel="noopener">《秃头生成器2》 </a>
</li>
<li><a href="https://medium.com/swlh/hairstyle-transfer-semantic-editing-gan-latent-code-b3a6ccf91e82" target="_blank" rel="noopener">NO.3</a>
</li>
</ul>
<p>Contribution（Problem）：</p>
<ol>
<li>解纠缠：Mapping Network</li>
<li>Noise Generator</li>
<li>AdaIN before all conv</li>
</ol>
<h2 id="structure">Structure：</h2>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930135941.png">
    <img alt="image-20210930135938114" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930135941.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930135941.png" style="display: block; margin: 0 auto;"
      alt="image-20210930135938114"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930161259.png">
    <img alt="image-20210930161258031" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930161259.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930161259.png" style="display: block; margin: 0 auto;"
      alt="image-20210930161258031"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="part1adain">Part1：AdaIN</h3>
<p>复习一下IN（inception normalization）</p>
<div>
$$ 
AdaIN(x_i,y) = y_{s,i}\frac{x_i-\mu(x_i)}{\sigma(x_i)}+y_{b,i}
 $$
</div>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930161124.png">
    <img alt="image-20210930161121411" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930161124.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930161124.png" style="display: block; margin: 0 auto;"
      alt="image-20210930161121411"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="part2noise-generator">Part2：Noise Generator</h3>
<p>通过独立分辨率的高斯误差生成器，独立生成误差，然后控制例如毛发，胡须，雀版等等的随机生成。</p>
<h3 id="part3-解纠缠mapping-function"><strong>Part3</strong> 解纠缠（Mapping Function）</h3>
<p>解纠缠定义：由线性空间组成的潜在空间，使得每个线性子空间控制一个变化因子。</p>
<p>如果使用原始输入的话，潜在空间各种因子的采样概率需要与训练数据集中的分布匹配，各factor就还是纠缠在一起，不能使得较好的独立性存在。</p>
<p><strong>解决方法：</strong></p>
<p>通过Mapping Network，将input Z -&gt; W，在 W这个latent layer中提取出来的factor，就不需要遵循既有的分布，实现了解纠缠，使得各个变量能够独立的对特征进行控制。</p>
<p><strong>附加问题：</strong></p>
<p>如何衡量解纠缠效果，空间因子的分离程度：“线性空间中的插值可能对图像产生非线性变化”基于latent space中的变化和图像发生的变化来衡量分离的效果，潜伏空间中较小的变化也应该导致的是图像上较小（平滑）的变化。</p>
<p><strong>度量标准：</strong></p>
<ul>
<li>
<p>基于感知的图像对距离**：**</p>
<p>（通过2个加权VGG16 Embedding 之间的距离），假如我们再潜在空间的分割时线性的，也就是每一段都是线性路径，就能使得线性变化成立，理论上无限细分是可行的，实际上使用Σ = 1e-4,所以Z中平均的感知距离为：Lz，同理求得W中的Lw</p>
</li>
<li>
<p>线性可分离性**：**</p>
<p>&ldquo;如果充分的解纠缠，则应该找到始终和各个变化因素相对应的方向向量&rdquo;。该度量标准是通过量化线性超平面，能够将隐含空间的点分成两个独立的集合的程度。这样每个集合能够对应图像的特定二值属性。（男女）</p>
<p>在判别过程中使用和判别器又相同架构的分类器：保留属性，生成图像，进行分类，去除低置信度，得到带标签的钱再空间向量，svm预测标签，进行分类，计算条件熵</p>
</li>
</ul>
<p>球面插值是归一化输入隐层空间中进行插值的最佳方法。</p>
<p>没有归一化的情况下就使用线性插值就好了</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930161347.png">
    <img alt="image-20210930161345507" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930161347.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930161347.png" style="display: block; margin: 0 auto;"
      alt="image-20210930161345507"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930161359.png">
    <img alt="image-20210930161358285" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930161359.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930161359.png" style="display: block; margin: 0 auto;"
      alt="image-20210930161358285"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h1 id="v2-analyzing-and-improving-the-image-quality-of-stylegan">V2 Analyzing and Improving the Image Quality of StyleGAN</h1>
<p><strong>Relted Work</strong>：Based on styleGAN.</p>
<p><a href="http://www.gwylab.com/pdf/stylegan2_chs.pdf" target="_blank" rel="noopener">中文译文</a>
</p>
<p><strong>Contribution</strong>（Problem）：</p>
<ol>
<li>重新设计了生成器归一化方法，<strong>改善了图像的质量</strong>：</li>
<li>同时路径长度调节器使得<strong>生成器的过程可逆</strong>，从而实现了网络可视化和方便对网络结构进行分析。</li>
</ol>
<p>解决生成图像中水滴伪影的问题，将StyleGAN中的感知路径作为新的正则化器。</p>
<p><strong>Part1</strong>：修改<strong>AdaIN</strong>的具体执行，消除伪像**</p>
<p>架构变化主要是：B-&gt;C-&gt;D</p>
]]></content:encoded>
    </item>
    <item>
      <title>YOLOv4</title>
      <link>https://aikenh.cn/posts/yolov4/</link>
      <pubDate>Sun, 03 Oct 2021 13:16:40 +0000</pubDate>
      <guid>https://aikenh.cn/posts/yolov4/</guid>
      <description>Optimal Speed and Accuracy of Object Detection</description>
      <content:encoded><![CDATA[<p>@AikenHong 20200726</p>
<p>基于YOLO v4 掌握一些CV方面训练的<strong>Trick</strong>，同时针对Typora的使用进行一个熟悉掌握。<a href="https://github.com/AlexeyAB/darknet" target="_blank" rel="noopener">GITHUB CODE</a>
</p>
<p>一些相关的参考资料</p>
<p>⚡️https://zhuanlan.zhihu.com/p/150127712</p>
<p>⚡ <a href="https://mp.weixin.qq.com/s?__biz=MzA3MzI4MjgzMw==&amp;mid=2650785604&amp;idx=1&amp;sn=46bd186e5291deded9f6ec1ae6a22649&amp;chksm=871a033ab06d8a2cff370a06e9e88f578a6c16a70231778ae2f997a8b30e347c6e746db10759&amp;mpshare=1&amp;scene=1&amp;srcid=0429kHitmMCPeF2JGN1XCzik&amp;sharer_sharetime=1588144165276&amp;sharer_shareid=484a4a951d2ad320314b6b56ee9a0ba8&amp;key=c53866ae67b2b8c4b46c89671357025dcdb6b895d1ebde603135230e484682a3552d924bf6126ecf72cb98361e1171f0f0381bee5bd456520dd201034c33ec48272d62ae73345cc914c2db9c6e943a10&amp;ascene=1&amp;uin=NTkyNDg4NjQw&amp;devicetype=Windows&#43;10&#43;x64&amp;version=62090070&amp;lang=zh_CN&amp;exportkey=ASfZUAGjes1A%2BJpXS1yNmT0%3D&amp;pass_ticket=GB56ClnZIrs5ENfLSAh4yF9tj54n041FM39bTg38LQuW%2FKDyBPyfqKLD8SDIZgE%2F" target="_blank" rel="noopener">机器之心YOLOv4</a>
</p>
<p>⚡️https://www.zhihu.com/question/390191723/answer/1177584901</p>
<p><strong>本文中一些其他的收获</strong></p>
<p>•  其他可替代的Object Detection的SOTA算法有哪些</p>
<p>•  BoS，BoF方法</p>
<p>•  简直是一个Tricks的综述</p>
<h2 id="abstract">Abstract</h2>
<p>本文对近期再CNN上的一些Feature方法进行了尝试组合，并实现了新的SOTA，其实就是一些<strong>通用的<strong><strong>Trick</strong></strong>的组合</strong>尝试，包括</p>
<p>•  加权残差连接（WRC）</p>
<p>•  Cross-Stage-Partial-connection，CSP</p>
<p>•  Cross mini-Batch Normalization，CmBN</p>
<p>•  自对抗训练（Self-adversarial-training，SAT）</p>
<p>•  Mish 激活（Mish-activation）</p>
<p>•  Mosaic 数据增强</p>
<p>•  DropBlock 正则化</p>
<p>•  CIoU 损失</p>
<p>基于该文章我们可以了解一下这些方法的主要思路和后续的应用价值。YOLOv4 更快，更准确，只需要比较小的计算需求即可</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930165042.png">
    <img alt="image-20210930165040810" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930165042.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930165042.png" style="display: block; margin: 0 auto;"
      alt="image-20210930165040810"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="introduction">INTRODUCTION</h2>
<p>•  更快更强，从速度和准确率，以及训练需求上提升实际运用价值</p>
<p>​	这里有一些其他的SOTA可以列一下：EfficientDet、ATSS，ASFT，CenterMask</p>
<p>•  AP：平均准确率 FPS：每秒传输帧率嘛？</p>
<p>主要贡献可总结如下</p>
<ol>
<li>
<p>建立了一个高效强大的目标检测模型。它使得每个人都可以使用 1080Ti 或 2080Ti 的 GPU 来训练一个快速准确的目标检测器。</p>
</li>
<li>
<p>验证了当前最优 Bag-of-Freebies 和 Bag-of-Specials 目标检测方法在检测器训练过程中的影响。</p>
<p>Bag-of-freebies: 仅仅只增加training cost或者只改变training strategy的方法。典型例子：数据增强
bag-of-specials: 增加少量推理成本，但能提高准确率的**插件模块（****plugin modules）和后处理方法（post-processing method）**被称为BoS。</p>
</li>
<li>
<p>修改了 SOTA 方法，使之更加高效，更适合单 GPU 训练。这些方法包括 CBN、PAN、SAM 等。</p>
<p>PAN: Path aggregation network for instance segmentation</p>
<p>SAM: CBAM: Convolutional block attention module</p>
</li>
</ol>
<h2 id="related-work">RELATED WORK</h2>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930165008.png">
    <img alt="image-20210930165005309" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930165008.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930165008.png" style="display: block; margin: 0 auto;"
      alt="image-20210930165005309"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><strong>基本架构</strong></p>
<ul>
<li>
<p>object detector 通常由backbone和head两部分构成，其中backbone是再imagenet上预训练的骨架</p>
<ul>
<li>GPU: VGG [68], ResNet [26], ResNeXt [86],or DenseNet [30]</li>
<li>CPU: SqueezeNet [31], MobileNet[28, 66, 27, 74], or ShuffleNet [97, 53]</li>
</ul>
</li>
<li>
<p>head则是用来预测物体类别和边界框的网络架构</p>
<ul>
<li>One-Stage: YOLO [61, 62, 63], SSD [50],and RetinaNet [45]</li>
<li>Anchor-free：CenterNet [13], CornerNet [37, 38], FCOS [78], etc.</li>
<li>Two-Stage:  R-CNN [19] series: fast R-CNN [18], faster R-CNN [64], R-FCN [9],and Libra R-CNN [58] anchor-free: Rep-Points[87]</li>
</ul>
</li>
<li>
<p>近年来在backbone和head之间插入neck用以收集不同stage的feature-maps FPN、PAN、BiFPN、NAS-FPN、etc.</p>
</li>
</ul>
<p>To sum up, an ordinary object detector is composed of several parts:</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930165142.png">
    <img alt="image-20210930165140911" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930165142.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930165142.png" style="display: block; margin: 0 auto;"
      alt="image-20210930165140911"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><strong>Bag-of-freebies:</strong></p>
<p>仅仅只增加training cost或者只改变training strategy的方法。典型例子：数据增强</p>
<ul>
<li>目标检测中的多种数据增强：包括对图像遮挡的处理，随机擦除和基本的数据增强，也有feature map中类似的操作</li>
<li>解决数据存在偏差的问题：例如数据不平衡</li>
<li>BoundingBox回归方法：MSE-》IoU，也就是一些边界回归上的损失函数，CIoU、GIoU、DIoU、MSE等</li>
</ul>
<p><strong>Bag of specials</strong></p>
<p>增加少量推理成本，但能提高准确率的**插件模块（plugin modules）和后处理方法（post-processing method）**被称为BoS。</p>
<p><strong>Plugin modules</strong>：例如扩大接受域，引入注意力机制，增强特征集成能力等等，</p>
<p><strong>post-processing method</strong>：筛选预测结果的方法</p>
<ul>
<li>
<p>扩大接受域：SPP（将SPM集成到CNN中）、ASPP、RFB。</p>
</li>
<li>
<p>Attention module：</p>
</li>
<li>
<p>Channel-Wise：SE</p>
</li>
<li>
<p>Point-Wise：SAM</p>
</li>
<li>
<p>feature integration：</p>
</li>
</ul>
<p><strong>将低层的物理特征集成到高层语义特征</strong></p>
<ul>
<li>skip connection、hyper-column</li>
<li>FPN出现后：SFAM、ASFF、BiFPN</li>
<li>activation function：</li>
<li>解决softmax和sigmoid中出现的梯度消失问题：ReLU、LReLU、PReLU、ReLU6、SELU、Swish、hard-Swish、Mish</li>
</ul>
<p><strong>post-process：</strong></p>
<p>–  NMS用于处理预测同一对象的一些BBox，并保留响应速度更快的BBox</p>
<p>–  还有一些相关变体</p>
<p>–  anchor-free的方法不需要这部分</p>
<h2 id="architecture">Architecture</h2>
<ol>
<li>
<p>找到最优的<strong>input network resolution</strong>，<strong>conv layer number</strong>， <strong>the parameter number(filter size2 * filters * channel / groups)</strong> <strong>以及</strong> **the number of layer outputs(filters)**之间的最有平衡</p>
</li>
<li>
<p>挑选能够增加感受域的额外单元（additional block），以及最佳参数聚合方法</p>
<p>YoloV4 的基本目标是提高生产系统中神经网络的运行速度，同时为并行计算做出优化，而不是针对低计算量理论指标（BFLOP）进行优化。YoloV4 的作者提出了两种实时神经网络：</p>
</li>
</ol>
<p>（Backbone）</p>
<p>•  对于 GPU，研究者在卷积层中使用少量组（1-8 组）：CSPResNeXt50 / CSPDarknet53；</p>
<p>•  对于 VPU，研究者使用了分组卷积（grouped-convolution），但避免使用 Squeeze-and-excitement（SE）块。具体而言，它包括以下模型：EfficientNet-lite / MixNet / GhostNet / MobileNetV3。</p>
<p>分类器和检测器需求上的区别：</p>
<p><strong>架构选择part1</strong></p>
<ol>
<li>
<p>CSPDarknet53&lt;-最终选择的一个较好的模型（backbone）</p>
</li>
<li>
<p>在cspdarknet52上添加了spp block，用PANet取代v3中的FPN，yolov3作为head</p>
</li>
</ol>
<p><strong>架构选择part2：selection of BoF or BoS</strong></p>
<p>CNN的优化通常有这几个方面：</p>
<ul>
<li>Activations: ReLU, leaky-ReLU, parametric-ReLU, ReLU6, SELU, Swish, or Mish</li>
<li>Bounding box regression loss: MSE, IoU, GIoU,CIoU, DIoU</li>
<li>Data augmentation: CutOut, MixUp, CutMix</li>
<li>Regularization method: DropOut, DropPath [36], Spatial DropOut [79], or <strong>DropBlock</strong></li>
<li>Normalization of the network activations by their mean and variance:</li>
</ul>
<p>Batch Normalization (BN) [32], Cross-GPU Batch Normalization (CGBN or SyncBN) [93], Filter Response Normalization (FRN) [70], or Cross-Iteration Batch Normalization (CBN) [89]</p>
<ul>
<li>Skip-connections: Residual connections, Weighted residual connections, Multi-input weighted residual connections, or Cross stage partial connections (CSP)</li>
</ul>
<p><strong>架构选择Part3</strong> ：额外的改进</p>
<p>使得架构能够更适合在单个GPU上进行运算，设计了一些改进</p>
<p>•  新的数据增强方法：mosaic &amp;SAT（self-Adversarial Training）</p>
<p>•  在遗传算法中使用了最佳的超参数</p>
<p>•  修改SAM，PAN和CmBN使得设计适合更有效的训练和检测</p>
<p>Mosaic（马赛克）数据增强，把四张图拼成一张图来训练，变相的等价于增大了mini-batch。这是从CutMix混合两张图的基础上改进；</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930165156.png">
    <img alt="image-20210930165154939" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930165156.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210930165156.png" style="display: block; margin: 0 auto;"
      alt="image-20210930165154939"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<hr>
<p><strong>Mosaic数据增强</strong></p>
<ol>
<li>
<p>Self-Adversarial Training(自对抗训练)，这是在一张图上，让神经网络反向更新图像，对图像做改变扰动，然后在这个图像上训练。这个方法，是图像风格化的主要方法，让网络反向更新图像来风格化图像（对风格化感兴趣，可以看看我写的一篇介绍<a href="https://zhuanlan.zhihu.com/p/105550915" target="_blank" rel="noopener">谷歌的一个实时任意风格化的文章</a>
）；对自身实行对抗攻击</p>
</li>
<li>
<p>跨最小批的归一化（Cross mini-batch Normal），在CBN的基础上改进；</p>
</li>
</ol>
<p><strong>BN, CBN，CmBN的对比</strong></p>
<ol>
<li>修改的SAM，从SAM的逐空间的attention，到逐点的attention；</li>
</ol>
<p>[image: https://pic4.zhimg.com/50/v2-440bfacec2a426272ef06e94a16837bb_hd.jpg?source=1940ef5c]</p>
<p><strong>SAM和修改的SAM对比图</strong></p>
<ol>
<li>修改的PAN，把通道从相加（add）改变为concat，改变很小；</li>
</ol>
<p>[image: https://pic4.zhimg.com/50/v2-a1f0ccf10cea594c1aebcc98111c6dd5_hd.jpg?source=1940ef5c][image: https://pic4.zhimg.com/80/v2-a1f0ccf10cea594c1aebcc98111c6dd5_720w.jpg?source=1940ef5c]</p>
<p>PAN和修改的PAN</p>
<p>最终整体架构表示：</p>
<h2 id="experiments">Experiments</h2>
<p>实验中的一些参数设置和具体的表达就从文章中看吧，还有各种trick的表达效果,其实很重要，可以省下很多的研究时间。</p>
<p>•  Influence of different features on Classifier training</p>
<p>•  Influence of different features on Detector training</p>
<p>•  Influence of different backbones and pretrained weightings on Detector training</p>
<p>•  Influence of different minibatch size on Detector training</p>
<p><strong>FAQ</strong></p>
<p>•  reception field 的理解，以及作用</p>
]]></content:encoded>
    </item>
    <item>
      <title>OW Object Detector</title>
      <link>https://aikenh.cn/posts/ow-od/</link>
      <pubDate>Tue, 28 Sep 2021 13:44:20 +0000</pubDate>
      <guid>https://aikenh.cn/posts/ow-od/</guid>
      <description>Open World Learning</description>
      <content:encoded><![CDATA[<p>@Aiken 2021</p>
<p>框架撞车系列，主要看看这一篇论文中怎么解决如下的问题👇，并从中借鉴和优化的我框架设计</p>
<h2 id="思路分析">思路分析</h2>
<h3 id="motivation">Motivation</h3>
<p><strong>模型实现的主要的两个TASK：</strong></p>
<ol>
<li>Open Set Learning ： 在没有明确监督的时候，将尚未引入的目标类别识别为未知</li>
<li>Incremental Learning：类别增量学习</li>
</ol>
<p><strong>实现这两个问题的主要思路：</strong></p>
<ul>
<li><strong>自动标注</strong>：借鉴RPN的class-agnostic，以及检测和分类的显著性指标的差异，找到并自动标注NewClass</li>
<li>**对比聚类：**使用prototype feature来进行聚类，同时计算Distance损失
it seems like contain a unknown prototype.</li>
<li>**energy based：**亥姆霍兹自由能公式？</li>
</ul>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210412171723896.png">
    <img alt="image-20210412171723896" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210412171723896.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210412171723896.png" style="display: block; margin: 0 auto;"
      alt="image-20210412171723896"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="energy-based"><strong>ENERGY BASED</strong></h3>
<p>Feature： $F$ , Label: $L$ ,  Energy: $E(F,l)$</p>
<p>能量函数倾向于将已知的类别分类到低熵的分布上，然后我们可以根据特征在能量空间上的划分来区分新类和旧类。然后我们可以根据logits表达的softmax形式，找到输出和Gibbs distribution的相关性：</p>
<div>
$$ 
p(l \mid \boldsymbol{f})=\frac{\exp \left(\frac{g_{l}(\boldsymbol{f})}{T}\right)}{\sum_{i=1}^{\mathrm{C}} \exp \left(\frac{g_{i}(\boldsymbol{f})}{T}\right)}=\frac{\exp \left(-\frac{E(\boldsymbol{f}, l)}{T}\right)}{\exp \left(-\frac{E(\boldsymbol{f})}{T}\right)}
 $$
</div>
<p>通过这个相关性，我们对自由能进行一个定义，以logits的形式表达</p>
<div>
$$ 
E(f:g) = -T log\sum_{i=1}^{C}exp(\frac{g_i(f)}{T})
 $$
</div>
<p>g实际上表示特征最后输出的logits，通过能量的映射函数，我们将聚类转移到能量域上做，置信度较高的类别和未知的新类实际上有一个比较明显区分的分界线。</p>
<p>实际上我觉得就是类似熵的形式，在本文中将softmax的形式和gibis自由能做了一个对比，然后相当于对logits映射到了能量的维度去做特征的对比聚类，同时也能看出，在能量这个隐层空间中，在能级上能对已知类别和未知类别之间有一个明显的区分，所以在能级上进行划分是一个比较合理的空间映射形式。</p>
<h3 id="alleviating-forgetting"><strong>Alleviating Forgetting</strong></h3>
<p>参数正则化方法：exemplar replay：动态扩张网络；元学习</p>
<p>增量学习中提到的一些贪婪的参数选择策略好像对SOTA的方法都有很大的优势；后续又有人发现存储少量的示例和replay的有效性在相关的Few-Shot Detect中式有效的。</p>
<p>本文采用相对简单的ORE方法来减缓灾难性遗忘的问题，也就是说存放了一组平衡的范例，在每个增量步骤后对模型进行微调，确保每个类最少有 $N_{ex}$ 个示例出现在例子集中。</p>
<blockquote>
<p>实际上说的就是每次增量学习之后都会进行数据集的混合然后朝着原本的方向进行一定的微调；好像也没有什么特别的把，具体的实现可能要参见代码。</p>
</blockquote>
<h3 id="workflow"><strong>Workflow</strong></h3>
<p>我认为是通过RPN和class-aware之间的插值直接直接标注的一个未知的类别，然后在后续直接让人类区标注感兴趣的样本，可能是从少到多的，并没有一个特定的POOL，原本的模型可能有预留的Unknown Class或者说是相应的预留输出节点，然后在获得新的数据标注之后，进行更新模型的训练，然后使用避免灾难性遗忘的策略去做，从而使得模型对新的类别存在认知，也不会忘记旧的类别的知识。</p>
]]></content:encoded>
    </item>
    <item>
      <title>Attention Mechanism</title>
      <link>https://aikenh.cn/posts/attention/</link>
      <pubDate>Tue, 28 Sep 2021 05:34:22 +0000</pubDate>
      <guid>https://aikenh.cn/posts/attention/</guid>
      <description>How to Understand Attention Mechanism</description>
      <content:encoded><![CDATA[<p>@Aiken 2020.9.16</p>
<p>对基本注意力机制的一些资料和理解做一些简单的汇总，着重分析基本思想原理，应用和实现（即 structure），还有一些Weakness和相应的解决方案。</p>
<p><strong>1.TODO-List：</strong></p>
<ul>
<li>根据Lil’Log的Attention？Attention！进行初步的整理</li>
<li>各个分类的具体含义分开整理，理解一部分整理一部分，可能结合实际的应用去整理吧。</li>
<li>其中很重要的一点是数学分析的部分，需要对数学原理进行整理和领会。</li>
</ul>
<h2 id="whats-attention-in-deep-learning">What’s Attention In Deep Learning</h2>
<p>在某种程度上，注意力是由我么如何关注视觉图像的不同区域或者我们如何关联同一个句子中的不同单词所启发的：针对于问题的不同，我们会对图像的某些具体的区域重视（某些区域在视觉中呈现高分辨率，而另一些则是低分辨率的情况），或者句子中的某些词重视的情况。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911182724.png">
    <img alt="image-20210118210915289" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911182724.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911182724.png" style="display: block; margin: 0 auto;"
      alt="image-20210118210915289"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>可以解释一个句子中紧密的上下文单词之间的关系，比如我们看到eating就会期待看到food，而color对于我们来说就没有那么重要。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911182729.png">
    <img alt="image-20210118210936862" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911182729.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911182729.png" style="display: block; margin: 0 auto;"
      alt="image-20210118210936862"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>简而言之，深度学习中的注意力就是针对不同问题下的重要性权重的向量，比如我们根据关联性，给上面的每个单词赋予一个相关性的向量权重，然后基于注意力加权后的总和作为目标的近似值。</p>
<h2 id="whats-wrong-with-seq2seq-model">What’s Wrong with Seq2Seq Model</h2>
<p>seq2swq旨在将再encoder-decoder的架构下，将输入序列转换为新序列，对两个序列的长度没有要求。</p>
<ul>
<li>Encoder：将输入序列转换成固定长度的context vector，用来概括整个源序列的信息</li>
<li>Decoder：使用context vector初始化，来进行解码（转换）</li>
</ul>
<p>这样的Encoder和Decoder架构都是Recurrent Neural Networks，就像LSTM和GRU架构。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911182731.png">
    <img alt="image-20210118214147224" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911182731.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911182731.png" style="display: block; margin: 0 auto;"
      alt="image-20210118214147224"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>缺陷：固定长度的context vector可能会导致序列信息的缺失，同时可能会无法记住长句子，同时也会丢失<strong>时序的对齐</strong>信息。所以Attention就诞生了。</p>
<p>:question:</p>
<h2 id="born-for-translation">Born for Translation</h2>
<p>这几个部分的研究都是基于NMT自然机器翻译，来进行分析的（文本非图像）</p>
<p><strong>原本的E-D</strong>是通过Encoder的最后一个hidden states构建单个Context Vector，而<strong>Attention</strong>
做的就是在Context Vec和Source之间建立一个Shortcut（简单的Feed Forword
Network），而源和目标的对齐由上下文向量来学习和控制。而上下文中应该consumes（包含）几个维度的信息</p>
<p>Encoder的hidden States；</p>
<p>Decoder的hidden States；</p>
<p>Source 和 Target之间的对齐信息；</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911182734.png">
    <img alt="image-20210119164039458" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911182734.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911182734.png" style="display: block; margin: 0 auto;"
      alt="image-20210119164039458"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>Encoder Decoder实际上都是RNN的架构，S实际上就是H，隐层状态，Decoder对EOS输出了一个初始的预测Y以后，推进Decoder的进程。</p>
<p>双向的recurrent network（bidirectional RNN）使得Encoder隐态同时考虑前后单词。而在Decoder中</p>
<p>s_t = f(s_{t-1},y_{t-1},c_t)</p>
<p>其中上下文向量c_t是输入序列的隐态之和，通过alignment score来进行加权。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911182738.png">
    <img alt="image-20210119171524970" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911182738.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911182738.png" style="display: block; margin: 0 auto;"
      alt="image-20210119171524970"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>$a_{t,i}$ 将作为输入i对输出t的隐态加权（相关性），在网络中共同训练，通过tanh来进行激活处理。Score则使用下面的策略：</p>
<div>
$$ 
score(st,hi)=v_a^Ttanh(Wa[st;hi])
 $$
</div>
<p>其中V, W都是对齐模型中学到的参数</p>
<p>最终对齐完成以后就会是：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183010.png">
    <img alt="image-20210120112808197" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183010.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183010.png" style="display: block; margin: 0 auto;"
      alt="image-20210120112808197"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="a-family-of-attention-mechanism">A Family of Attention Mechanism</h2>
<h3 id="summary">Summary</h3>
<p>由于这个良好的理论基础和实现效果，以及对序列的良好兼容性，这样的算法就被很快的拓展到了计算机视觉的领域中。（学 科 交 叉）</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183207.png">
    <img alt="image-20210120162959426" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183207.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183207.png" style="display: block; margin: 0 auto;"
      alt="image-20210120162959426"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>这些不同的score方法实际上就是对每个position上的input和当前位置（通常用上一个时刻的state）来进行相关性建模，针对这些相关性建模，来确定输入对于下一个状态的影响因子，也就是得到一个context向量。这实际上就是注意力机制的核心理念把。</p>
<p>Referred to as “concat” in Luong, et al,
2015 and as “additive attention” in Vaswani, et al,
2017.(^) It adds a scaling factor 1/n−−√1/n,
motivated by the concern when the input is large, the
softmax function may have an extremely small gradient, hard for efficient learning.</p>
<p>下面对一些更广泛类型的注意力机制做一个摘要性的总结</p>
<h3 id="self-attention">Self-Attention</h3>
<p>这个已经在我的Onenote中整理过了，大概看看就好。这里只讲了一些应用上的点，</p>
<p>自我注意，内部注意力，也就是自我内部关联的注意力关系获取；</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183010.png">
    <img alt="image-20210120164912683" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183010.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183010.png" style="display: block; margin: 0 auto;"
      alt="image-20210120164912683"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="soft-vs-hard-attention">Soft vs Hard Attention</h3>
<p>Image Caption《show, attend and tell》，CNN获取特征，LSTM解码器利用卷积功能来逐一生成单词。通过Attention 来学习权重，可视化如下：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183524.png">
    <img alt="image-20210120165709998" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183524.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183524.png" style="display: block; margin: 0 auto;"
      alt="image-20210120165709998"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>根据注意力是访问整个图像还是访问图像的一个patch来定义hard和soft attention。</p>
<p>**Soft Attention：**就是普通的全图Attention，将权重放在图像的所有色块上，基本没啥区别</p>
<ul>
<li>Pro: 模型平滑容易微分</li>
<li>Con：expensive when the source image is large</li>
</ul>
<p>**Hard Attention：**一次只处理一小块图像，其实就相当于用0/1去对图像区域进行<a href="https://www.pianshen.com/article/86961257993/" target="_blank" rel="noopener">硬编码</a>
，只对一部分的图像进行处理，但是这种方式的技术实现我还是没什么概念，后面可以专门研究一下。</p>
<ul>
<li>Pro：推理计算需求比较小</li>
<li>Con：不可微分，需要用更复杂的技术来进行训练（例如variance reduction or reinforcement learning）</li>
</ul>
<h3 id="global-vs-loacal-attention">Global vs Loacal Attention</h3>
<p>Global实际上就和soft是类似的，而局部注意力机制更像是hard和soft之间的一个融合，对改进hard使其可以微分；</p>
<blockquote>
<p>the model first predicts a single aligned position for the current target word
and a window centered
around the source position is then used to compute a context vector.</p>
</blockquote>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183441.png">
    <img alt="image-20210120171755507" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183441.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183441.png" style="display: block; margin: 0 auto;"
      alt="image-20210120171755507"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>后面提到了一些神经图灵机的内容就是一些基本的计算机制，实际上可能是启发LSTM设计擦除算法设计的根源。</p>
<h2 id="neural-turing-machines">Neural Turing Machines</h2>
<h3 id="attention-mechanisms">Attention Mechanisms</h3>
<p>可以将权重的看作一个神经图灵机的寻址权重：（基于位置或者基于内容的两种方式）</p>
<p><strong>Content-based addressing:</strong></p>
<p>基于内容寻址的权重设置从输入行和存储行提取的键值向量之间的相似度来创建关注向量：权重的具体计算通过余弦相似度后进行softmax归一化来进行权重的分配。</p>
<p>另外通过β系数来放大或者减弱分布的焦点。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183438.png">
    <img alt="image-20210120215549507" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183438.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183438.png" style="display: block; margin: 0 auto;"
      alt="image-20210120215549507"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><strong>Interpolation</strong>
通过interpolation gate scalar $g_t$ 将生成的上下文向量和上一步生成的注意力权重进行混合</p>
<div>
$$ 
w^g_t = g_tw^c_t + (1-g_t)w_{t-1}
 $$
</div>
<p><strong>Location-baesd addressing</strong>
基于位置的寻址，对注意力向量中不同位置的值进行求和，通过对允许的整数偏移位置中的权重来进行参数加权。这相当于是一个一维卷积来测试偏移量。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183435.png">
    <img alt="image-20210120220824648" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183435.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183435.png" style="display: block; margin: 0 auto;"
      alt="image-20210120220824648"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>然后对注意力的分布进行锐化处理，使用γ参数</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183433.png">
    <img alt="image-20210120221036004" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183433.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183433.png" style="display: block; margin: 0 auto;"
      alt="image-20210120221036004"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>完整的注意力workflow为：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183429.png">
    <img alt="image-20210120221108972" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183429.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183429.png" style="display: block; margin: 0 auto;"
      alt="image-20210120221108972"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="pointer-network">Pointer Network</h2>
<p>解决的是输入输出都是顺序数据的问题。</p>
<h2 id="transformer-introduction">Transformer Introduction</h2>
<p><strong>Attention is all u need</strong>
：提出的重要的Transformer的这种架构，使得算法能够完全基于注意力机制，而不需要序列对齐的recurrent Network。</p>
<h3 id="keyvalue-and-query">Key,Value and Query</h3>
<p><strong>这一块还是详细解读一下，这里说的太粗略了，没讲清楚。</strong></p>
<p>Transformer的主要重要的架构在于multi-head和self-attention，Transformer将输入堪称一个key-value pairs，均为输入长度n。</p>
<div>
$$ 
Attention(Q,K,V)=softmax(\frac{Q K^⊤} {\sqrt{n}})V
 $$
</div>
<p>Key Value Query 到底都是些什么东西。</p>
<h2 id="encoder-decoder-and-taxonomy-of-attention">Encoder-Decoder and Taxonomy of Attention</h2>
<p>基本的encoder-decoder是基于对序列处理的问题提出的，通常情况下针对的是输入输出都是序列的计算模型。下图a展示了<strong>典型的E-D机制</strong>，以及加入了self-attention的情况b。（文中提到了一些E-D机制的问题）</p>
<blockquote>
<p>Seq2Seq的RNN序列模型Encoder需要把之前的输入最终转化成单一的ht（定长），可能会造成序列信息的丢失，同时他只能<strong>平权的</strong>考虑输入，不能有所<strong>重点</strong>。同时对于<strong>时序对齐</strong>信息也会丢失，这对结构化特别重要</p>
</blockquote>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183425">
    <img alt="img" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183425"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183425" style="display: block; margin: 0 auto;"
      alt="img"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>注意力机制，在实现上就是通过在体系架构中，嵌入一个额外的前馈神经网络，来进行学习额外的参数（作为Decoder的补充输入，作为序列和之前信息的补充），而且通常，这个前馈的神经网络是需要和encoder-decoder协同训练的，也就是需要和整体网络<strong>共同训练</strong>。</p>
<blockquote>
<p>训练层面是否存在一些特殊的情况，对于一些特殊的Attention 模型，是否需要一些特殊的训练机制。这点如果看到的话，建议需要整理一下</p>
</blockquote>
<p>在<strong>Survey</strong>中，对注意力机制基于多种标准进行了分类，具体的分类情况可以依下图所示，还有一些具体方法的实现。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183358">
    <img alt="img" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183358"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183358" style="display: block; margin: 0 auto;"
      alt="img"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183402.png">
    <img alt="uploading-image-657692.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183402.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183402.png" style="display: block; margin: 0 auto;"
      alt="uploading-image-657692.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>对于几种分类方式，可以参考几个译文的解读，但是我觉得说的并不清楚，后续就分别针对各种方法进行分析吧。</p>
<p>BTW：在RNN等循环结构不能并行化处理的条件下，提出的类似AM的<strong>Transformer</strong>（Attention is all u
need）结构，他的encoder和decoder由两个子层堆叠而来：Feed Forward Network 和 Multi-head self attention。</p>
<blockquote>
<p>Position-wise FFN：获取输入的顺序，在encoder阶段，对于每一个token既生成content embedding也生成position encoding。</p>
<p>Multi-Head Self-Attention：在每个子层中使用self - attention来关联标记及其在相同输入序列中的位置，几个注意力层并行堆叠，对于相同的输入有不同的线性转换。这使得模型能够捕获输入的不同方面，提高表达能力。</p>
</blockquote>
<h2 id="transformer-and-self-attention">Transformer and Self-Attention</h2>
<p>参考论文以及参考资料1 AND 《Attention is all you need》</p>
<p><strong>Self-Attention ：</strong></p>
<p>下图这一段整的明明白白，把整个框架说的比较明白，对输入的embedding（分别做3次卷积，图像输入的情况），分成Query，Key，Value，然后如图进行后续的操作</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183407.png">
    <img alt="image-20200926224839989" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183407.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183407.png" style="display: block; margin: 0 auto;"
      alt="image-20200926224839989"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183414.png">
    <img alt="image-20200927160231116" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183414.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911183414.png" style="display: block; margin: 0 auto;"
      alt="image-20200927160231116"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>图2就表示了在CV领域，为什么需要将输入做完卷积以后再成进去，而其中的scale由于图片和序列是不一致的，他们的size本来就是统一的（基本规范的数据集中），那么就可以省略掉这一步，从而直接进行softmax，相当于在预处理的时候已经进行了这样的归一操作。</p>
<p>self-attention 是 Transformer的基础，通过<strong>多个Self-Attention组成的Multi-head Attention</strong> 就是Transformer模型的基本结构。</p>
<p>Multi-head Attention</p>
<h2 id="reference">Reference</h2>
<p>参考资料</p>
<p><a href="https://zhuanlan.zhihu.com/p/47282410" target="_blank" rel="noopener">Attention机制详解2：self-attention &amp; Transformer</a>
</p>
<p><a href="https://jalammar.github.io/illustrated-transformer/" target="_blank" rel="noopener">origin document of ↑</a>
</p>
<p><a href="https://www.jianshu.com/p/8115c7cebc59" target="_blank" rel="noopener">Attention的数学原理</a>
</p>
<p>Survey:</p>
<ul>
<li>
<p>《An Attentive Survey of Attention Models》 mendeley</p>
</li>
<li>
<p><a href="https://www.cnblogs.com/ydcode/p/11040811.html" target="_blank" rel="noopener">论文翻译和解读1</a>
  :zap:</p>
</li>
<li>
<p><a href="https://blog.csdn.net/qq_29305911/article/details/89380387" target="_blank" rel="noopener">论文解读和翻译2</a>
</p>
</li>
<li>
<p><a href="https://zhuanlan.zhihu.com/p/62445564" target="_blank" rel="noopener">论文解读和翻译3</a>
</p>
</li>
</ul>
<p>Transformer:</p>
<ul>
<li>《Attention is all you need》Mendeley &amp;OneNote</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>EfficientNet</title>
      <link>https://aikenh.cn/posts/efficientnet/</link>
      <pubDate>Tue, 28 Sep 2021 05:34:22 +0000</pubDate>
      <guid>https://aikenh.cn/posts/efficientnet/</guid>
      <description>&lt;p&gt;Tags: Paper
URL1: &lt;a href=&#34;https://arxiv.org/pdf/1905.11946.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://arxiv.org/pdf/1905.11946.pdf&lt;/a&gt;

URL2: &lt;a href=&#34;https://arxiv.org/pdf/2104.00298.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://arxiv.org/pdf/2104.00298.pdf&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;提出了一种模型缩放策略，如何更高效的平衡网络的深度、宽度、和图片分辨率
&lt;strong&gt;1. Efficient Net: Rethinking Model Scaling for Convolutional Neural Networks
2. EfficientNetV2: Smaller Models and Faster Training&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;@Aiken H 2021 find detail to code his&lt;/p&gt;
&lt;h1 id=&#34;efficient-net-v1&#34;&gt;Efficient Net V1&lt;/h1&gt;
&lt;p&gt;除了提出了缩放策略以外，还使用神经架构搜索还建立了一个新的baseline network，得到了一系列模型。&lt;/p&gt;
&lt;p&gt;平衡网络宽度、深度、分辨率至关重要，这种平衡可以通过简单的恒定比率缩放维度来实现，于是我们&lt;strong&gt;提出了一种简单有效的复合缩放&lt;/strong&gt;方法。&lt;/p&gt;
&lt;p&gt;
&lt;div class=&#34;post-img-view&#34;&gt;
  &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210610180603496.png&#34;&gt;
    &lt;img alt=&#34;https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210610180603496.png&#34; loading=&#34;lazy&#34; src=&#34;https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210610180603496.png&#34;class=&#34;responsive-image&#34; src=&#34;https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210610180603496.png&#34; style=&#34;display: block; margin: 0 auto;&#34;
      alt=&#34;https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210610180603496.png&#34;  /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;script&gt;
  document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
      var images = document.querySelectorAll(&#34;.responsive-image&#34;);
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + &#34;px&#34;;
      });
  });
&lt;/script&gt;
&lt;/p&gt;
&lt;p&gt;复合缩放的物理意义：输入图像更大的话就需要更多层来增加感受野和更多通道，从而能在更大的图像上捕获更多细粒度的图案，而宽度和深度（对于表达能力来说很重要）之间也存在着一定的关系，“我们”是第一个对此进行了建模的。&lt;/p&gt;
&lt;p&gt;从各个维度单独的进行缩放能发现都存在着增益瓶颈，如何去得到这么一个合适的等比缩放增益&lt;/p&gt;
&lt;h2 id=&#34;motivation-and-method&#34;&gt;Motivation and Method&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;一些直观上的motivation，以及假想&lt;/strong&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Tags: Paper
URL1: <a href="https://arxiv.org/pdf/1905.11946.pdf" target="_blank" rel="noopener">https://arxiv.org/pdf/1905.11946.pdf</a>

URL2: <a href="https://arxiv.org/pdf/2104.00298.pdf" target="_blank" rel="noopener">https://arxiv.org/pdf/2104.00298.pdf</a>
</p>
<p>提出了一种模型缩放策略，如何更高效的平衡网络的深度、宽度、和图片分辨率
<strong>1. Efficient Net: Rethinking Model Scaling for Convolutional Neural Networks
2. EfficientNetV2: Smaller Models and Faster Training</strong></p>
<hr>
<p>@Aiken H 2021 find detail to code his</p>
<h1 id="efficient-net-v1">Efficient Net V1</h1>
<p>除了提出了缩放策略以外，还使用神经架构搜索还建立了一个新的baseline network，得到了一系列模型。</p>
<p>平衡网络宽度、深度、分辨率至关重要，这种平衡可以通过简单的恒定比率缩放维度来实现，于是我们<strong>提出了一种简单有效的复合缩放</strong>方法。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210610180603496.png">
    <img alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210610180603496.png" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210610180603496.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210610180603496.png" style="display: block; margin: 0 auto;"
      alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210610180603496.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>复合缩放的物理意义：输入图像更大的话就需要更多层来增加感受野和更多通道，从而能在更大的图像上捕获更多细粒度的图案，而宽度和深度（对于表达能力来说很重要）之间也存在着一定的关系，“我们”是第一个对此进行了建模的。</p>
<p>从各个维度单独的进行缩放能发现都存在着增益瓶颈，如何去得到这么一个合适的等比缩放增益</p>
<h2 id="motivation-and-method">Motivation and Method</h2>
<p><strong>一些直观上的motivation，以及假想</strong></p>
<ol>
<li>不同的缩放维度不是独立的</li>
<li>直观上，对于更高分辨率的图像我们应该增加网络深度。
这样更大的感受野可以帮助捕捉更大图像中包含的更多像素的相似特征</li>
<li>相应的，更高分辨率的图像也应该增加网路的深度以便再高分辨率图像中捕获具有更多像素的更细粒度的图案。</li>
</ol>
<p><strong>基于实验最终得到了这样的结果：</strong></p>
<div>
$$ depth: d = \alpha^\phi $$
</div>
<div>
$$ width: w = \beta^\phi $$
</div>
<div>
$$ resolution: r = \gamma^\phi $$
</div>
<div>
$$ s.t. \alpha · \beta^2 · \gamma^2 \approx 2 $$
</div>
<div>
$$ \alpha \geq 1, \beta \geq 1, \gamma \geq 1 $$
</div>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911211033.jpg">
    <img alt="https://pic1.zhimg.com/v2-c98089649e1dd2a1e2f461347375a304_r.jpg" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911211033.jpg"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911211033.jpg" style="display: block; margin: 0 auto;"
      alt="https://pic1.zhimg.com/v2-c98089649e1dd2a1e2f461347375a304_r.jpg"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><strong>求解方法：</strong></p>
<ol>
<li>固定φ，然后通过网格搜索得到最基本的模型 Efficient Net-B0</li>
<li>固定α、β、γ的值，使用不同的φ，得到相应的B1 -B7</li>
</ol>
<h2 id="experience-detail">Experience Detail</h2>
<p><a href="https://github.surf/rwightman/pytorch-image-models/blob/HEAD/timm/models/efficientnet_blocks.py" target="_blank" rel="noopener">github.surf</a>
</p>
<p><a href="https://github.surf/facebookresearch/pycls/blob/HEAD/pycls/models/effnet.py" target="_blank" rel="noopener">github.surf</a>
</p>
<p><a href="https://blog.csdn.net/weixin_43915511/article/details/108285329?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~aggregatepage~first_rank_v2~rank_aggregation-2-108285329.pc_agg_rank_aggregation&amp;utm_term=efficientnet%E7%BD%91%E7%BB%9C%E7%BB%93%E6%9E%84&amp;spm=1000.2123.3001.4430" target="_blank" rel="noopener">EfficientNet网络结构图_LYS_1129的博客-CSDN博客_efficientnet网络结构</a>
</p>
<p><a href="https://cloud.tencent.com/developer/article/1699699" target="_blank" rel="noopener">图解EfficientNet模型的完整细节</a>
</p>
<p><a href="https://blog.csdn.net/bblingbbling/article/details/107113806" target="_blank" rel="noopener">EfficientNet网络解析_bblingbbling的博客-CSDN博客_efficientnet网络结构</a>
</p>
<p><a href="https://blog.csdn.net/weixin_43509698/article/details/113824833" target="_blank" rel="noopener">EfficientNet B0-B7 网络参数_繁华落尽，寻一世真情的博客-CSDN博客</a>
</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210611001122494.png">
    <img alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210611001122494.png" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210611001122494.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210611001122494.png" style="display: block; margin: 0 auto;"
      alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210611001122494.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>从第三个连接中，我们可以整理出那些需要input的相关参数，然后输入网络中去建立该Model。</p>
<h3 id="实现中的问题">实现中的问题：</h3>
<p>blockN</p>
<ol>
<li>stride和padding在各个重复组合层中间的变化（只有DW卷积改变Imageview）（堆叠的层不改变相应的HW），也是由第一个层去进行处理</li>
<li>channel，在各个组合层之间的变化（堆叠的层刚好不改变channel数目）</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>Colab 使用的问题记录</title>
      <link>https://aikenh.cn/posts/googlecolab/</link>
      <pubDate>Tue, 28 Sep 2021 05:34:21 +0000</pubDate>
      <guid>https://aikenh.cn/posts/googlecolab/</guid>
      <description>google&amp;#39;s GPU-server</description>
      <content:encoded><![CDATA[<p>@Aiken 2020</p>
<p>在使用Google Colab的时候会有一些常见的使用错误，然后我们记录一些常见的错误的解决方案，方便后续使用。</p>
<p><strong>INDEX：</strong></p>
<ul>
<li>
<p>命令行参数的输入问题</p>
</li>
<li>
<p>tensorboard的执行方法</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 在colab中写的时候要把前面的符号也写上</span>
</span></span><span class="line"><span class="cl">%load_ext tensorboard  
</span></span><span class="line"><span class="cl">%tensorboard --logdir <span class="s1">&#39;./runs&#39;</span>  </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>command命令的使用：包括库安装和卸载之类的。
主要就是在命令前+！</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">!/opt/bin/nvidia-smi
</span></span><span class="line"><span class="cl"><span class="c1"># 下面顺便解决了一下</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ImportError: cannot import name &#39;PILLOW_VERSION&#39;(版本问题)</span>
</span></span><span class="line"><span class="cl">!pip uninstall pillow
</span></span><span class="line"><span class="cl">!pip install <span class="nv">pillow</span><span class="o">==</span>5.2.0</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Docker Configuration00 Install on WSL2</title>
      <link>https://aikenh.cn/posts/%E5%9C%A8windows%E4%B8%8A%E5%AE%89%E8%A3%85docker/</link>
      <pubDate>Tue, 28 Sep 2021 05:34:21 +0000</pubDate>
      <guid>https://aikenh.cn/posts/%E5%9C%A8windows%E4%B8%8A%E5%AE%89%E8%A3%85docker/</guid>
      <description>install docker on wsl2 with portainer</description>
      <content:encoded><![CDATA[<p>基于 WSL2 对于 Docker 的适配，本文介绍 Windows 下利用 WSL2 对 Docker 的安装和部署，对于 WSL2 的安装可以参考上篇文章： <a href="https://aikenh.cn/cn/WSL2/" target="_blank" rel="noopener">Windows Configuration01 WSL2 - AikenH Blogps</a>
</p>
<h2 id="install-docker-on-windows">Install Docker on Windows</h2>
<p>该部分主要介绍以下几内容：安装，存储盘迁移，连接 WSL2 发行版，完成了这几步之后就可以畅游 Docker 世界了。</p>
<blockquote>
<p>前置：先安装好一个 WSL2 的发行版，win11 自带 WSL2</p>
</blockquote>
<p>首先，官网 <a href="https://www.docker.com/" target="_blank" rel="noopener">Docker:</a>
 下载 Docker Desktop for windows，安装基于 WSL2 的 docker，安装完成后 Docker 的发行版和存储目录会默认存放在，该地址可以用来确认后续的迁移状态。</p>
<ul>
<li>Docker-Desktop/data：<code>%LOCALAPPDATA%/Docker/wsl</code></li>
<li>WSL2：<code>%LOCALAPPDATA%/packages/c......./local_state</code></li>
</ul>
<p>安装完后首先打开 docker 确认没有其他异常问题报警，然后就可以对存储空间和 Desktop 进行迁移（option），迁移的方式可以参考上文中对 WSL2 的迁移。下面给出脚本便于使用：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">wsl</span> <span class="p">-</span><span class="n">-shutdown</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 系统导出</span>
</span></span><span class="line"><span class="cl"><span class="n">wsl</span> <span class="p">-</span><span class="n">-export</span> <span class="nb">docker-desktop</span><span class="n">-data</span> <span class="s2">&#34;D:\docker\docker-desktop-data.tar&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">wsl</span> <span class="p">-</span><span class="n">-export</span> <span class="nb">docker-desktop</span> <span class="s2">&#34;D:\docker\docker-desktop.tar&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 删除原系统</span>
</span></span><span class="line"><span class="cl"><span class="n">wsl</span> <span class="p">-</span><span class="n">-unregister</span> <span class="nb">docker-desktop</span><span class="n">-data</span>
</span></span><span class="line"><span class="cl"><span class="n">wsl</span> <span class="p">-</span><span class="n">-unregister</span> <span class="nb">docker-desktop</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 挂载新目录</span>
</span></span><span class="line"><span class="cl"><span class="n">wsl</span> <span class="p">-</span><span class="n">-import</span> <span class="nb">docker-desktop</span> <span class="n">D:</span><span class="p">\</span><span class="n">docker</span><span class="p">\</span><span class="nb">docker-desktop</span> <span class="n">D:</span><span class="p">\</span><span class="n">docker</span><span class="p">\</span><span class="nb">docker-desktop</span><span class="p">.</span><span class="py">tar</span>
</span></span><span class="line"><span class="cl"><span class="n">wsl</span> <span class="p">-</span><span class="n">-import</span> <span class="nb">docker-desktop</span><span class="n">-data</span> <span class="n">D:</span><span class="p">\</span><span class="n">docker</span><span class="p">\</span><span class="nb">docker-desktop</span><span class="n">-data</span> <span class="n">D:</span><span class="p">\</span><span class="n">docker</span><span class="p">\</span><span class="nb">docker-desktop</span><span class="n">-data</span><span class="p">.</span><span class="py">tar</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 建立软连接（需要再cmd中执行，powershell中可能识别不了mklink命令）</span>
</span></span><span class="line"><span class="cl"><span class="c"># 否则可能会导致 docker-desktop-data 无法正确启动，导致重启后掉盘</span>
</span></span><span class="line"><span class="cl"><span class="n">mklink</span> <span class="s2">&#34;C:\Users\{user-name}\AppData\Local\Docker\wsl\data\ext4.vhdx&#34;</span> <span class="s2">&#34;D:\docker\docker-desktop-data\ext4.vhdx&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>迁移完成后重启 docker 即可，至此，安装就算完成了。</p>
<h2 id="basic-setting">Basic Setting</h2>
<p>为了发挥完整的性能，以及更容易执行 volume 参数进行 data 的挂载，这边强烈建议在 wsl2 中使用 docker！为此，在 docker-desktop 中需要设置如下的几个地方：</p>
<blockquote>
<p>例如 alist 镜像，在 wsl2 中设置好了 volume 参数，把 data 准确的挂载出来后，数据就不会再 docker 重启的时候丢失了。</p>
</blockquote>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230330085804.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230330085804.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230330085804.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>设置完成后，在 WSL2 中就可以识别和执行 Docker 命令了，后续对 docker、docker-compose 的操作都在 WSL2 中完成即可，接下来就可以在 docker 的应用市场中愉快的淘金了。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230330090709.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230330090709.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230330090709.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="docker-apps-personal-recommand-">Docker Apps( personal recommand )</h2>
<p>后续会对其中的一些来做简单的部署和讲解，其实很多都挺适合在 NAS 上部署的，结合内网穿透技术能有一个更好的体验，后面也可以简单介绍以下内网穿透。</p>
<ol>
<li>Alist 个人云管理中心，统一管理，访问，在线观看等，强力推荐</li>
<li>Immich 局域网图片备份和管理中心，有移动端 APP，自动备份，权限隔离，</li>
<li>Kavita 图书、PDF 管理中心（还在找更好的 pdf 中心）</li>
<li>wikijs 个人 wikipage</li>
<li>foamzou/melody：音乐资源搜索和自动上传网易云云盘</li>
<li>memos：个人备忘录中心</li>
</ol>
<p>想要一个能够同时管理书籍和论文的 PDF 管理中心，最好能够集成一个比较好的 PDF 阅读和标记工具（比如直接用 Edge 把），不知道有没有类似的。</p>
]]></content:encoded>
    </item>
    <item>
      <title>寻路算法 Aster</title>
      <link>https://aikenh.cn/posts/astar/</link>
      <pubDate>Tue, 28 Sep 2021 05:34:21 +0000</pubDate>
      <guid>https://aikenh.cn/posts/astar/</guid>
      <description>A*算法，最短寻路算法，Dijkstra的变体的Py实现</description>
      <content:encoded><![CDATA[<p>A* 是一种在平面图形上计算最优路径的方法，通常用来做 2D 游戏的最短寻路，该算法是一种 Dijkstra 算法的变体，使用启发式的策略来提高算法的搜索效率。</p>
<p><a href="https://zh.wikipedia.org/wiki/A*%E6%90%9C%E5%B0%8B%E6%BC%94%E7%AE%97%E6%B3%95" target="_blank" rel="noopener">wikipedia</a>
；<a href="https://medium.com/@nicholas.w.swift/easy-a-star-pathfinding-7e6689c7f7b2" target="_blank" rel="noopener">medium</a>
；<a href="https://www.pythonf.cn/read/123915" target="_blank" rel="noopener">pythonf</a>
</p>
<h2 id="基本思想">基本思想</h2>
<p>基于启发式的方法，基于BFS去做最短路径搜索，借助类似Manhattan距离作为启发，每次加入后续的多个点，然后按照后续点的属性去排序，不断的加入close的区间，直到第一次遍历到终点就是最短的路径。</p>
<div>
$$ f(n) = g(n) + h(n) $$
</div>
<p>f代表的是经过当前点，从起点到最终点的距离，g代表的是从起点到当前节点的距离，h代表的是启发式方法到终点的距离。</p>
<p>维护三个list：open(候选列表)、close（状态确定的列表）、children（等待操作的列表）</p>
<p>首先用 bfs 的方法，找到当前节点的可达后续节点，将这些节点加入 children，确定 child 不在 close_list 中后（即在 open 中）则判断哪个是最优解，然后更新 openlist 和 closelist 。</p>
<p>即：每次遍历的当前节点都从 open 中总距离最小的选，然后放入 close。直到 openlist 为空。</p>
<h3 id="相关类别定义">相关类别定义</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">node</span><span class="p">():</span> 
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">parent</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">position</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">parent</span> <span class="o">=</span> <span class="n">parent</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">position</span> <span class="o">=</span> <span class="n">position</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">g</span> <span class="o">=</span> <span class="mi">0</span> 
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">h</span> <span class="o">=</span> <span class="mi">0</span> 
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">f</span> <span class="o">=</span> <span class="mi">0</span> 
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">o</span><span class="p">:</span> <span class="nb">object</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">o</span><span class="o">.</span><span class="n">position</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">position</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="具体代码实现">具体代码实现</h3>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">asterS</span><span class="p">(</span><span class="nb">map</span><span class="p">,</span><span class="n">slope</span><span class="p">,</span><span class="n">start</span><span class="p">,</span><span class="n">end</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># 在astar算法的基础上，我们需要加入的是高度的约束</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># 阻碍的条件是高度不同同时没有slope的存在，这种就是wall</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># 其余的和Astar算法应该是一样的</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># init the start and end node</span>
</span></span><span class="line"><span class="cl">    <span class="n">start_node</span> <span class="o">=</span> <span class="n">node</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span><span class="n">start</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">end_node</span> <span class="o">=</span> <span class="n">node</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span><span class="n">end</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># init the open and closed lists</span>
</span></span><span class="line"><span class="cl">    <span class="n">open_list</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">    <span class="n">close_list</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># add the start node to the open list</span>
</span></span><span class="line"><span class="cl">    <span class="n">open_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">start_node</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># loop util find the end_node </span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="nb">len</span><span class="p">(</span><span class="n">open_list</span><span class="p">)</span><span class="o">&gt;</span><span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># make the best node as current_node</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># init 1 </span>
</span></span><span class="line"><span class="cl">        <span class="n">current_node</span> <span class="o">=</span> <span class="n">open_list</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="n">current_index</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">index</span><span class="p">,</span> <span class="n">nod</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">open_list</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">nod</span><span class="o">.</span><span class="n">f</span><span class="o">&lt;</span><span class="n">current_node</span><span class="o">.</span><span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="n">current_node</span> <span class="o">=</span> <span class="n">nod</span>
</span></span><span class="line"><span class="cl">                <span class="n">current_index</span> <span class="o">=</span> <span class="n">index</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1"># pop the curr node off open list, add to close list </span>
</span></span><span class="line"><span class="cl">        <span class="n">open_list</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="n">current_index</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">close_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">current_node</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># terminal conditions (reach the end node )</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">current_node</span> <span class="o">==</span> <span class="n">end_node</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">path</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">            <span class="k">while</span><span class="p">(</span><span class="n">current_node</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">                <span class="n">path</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">current_node</span><span class="o">.</span><span class="n">position</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="n">current_node</span> <span class="o">=</span> <span class="n">current_node</span><span class="o">.</span><span class="n">parent</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="c1"># return the path we find.</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">path</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1"># the body of the loop: update the nodes</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># find the available children nodes</span>
</span></span><span class="line"><span class="cl">        <span class="n">children</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># define the adjacent squares </span>
</span></span><span class="line"><span class="cl">        <span class="n">positions</span> <span class="o">=</span> <span class="p">[(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">),(</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">),(</span><span class="mi">0</span><span class="p">,</span><span class="o">-</span><span class="mi">1</span><span class="p">),(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">pos</span> <span class="ow">in</span> <span class="n">positions</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="c1"># get childrens positions</span>
</span></span><span class="line"><span class="cl">            <span class="n">node_pos</span> <span class="o">=</span> <span class="p">(</span><span class="n">current_node</span><span class="o">.</span><span class="n">position</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="n">pos</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">current_node</span><span class="o">.</span><span class="n">position</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">+</span><span class="n">pos</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">            
</span></span><span class="line"><span class="cl">            <span class="c1"># make sure within range  </span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">node_pos</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">node_pos</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="nb">map</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="ow">or</span> <span class="n">node_pos</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">node_pos</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="nb">map</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl">                <span class="k">continue</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="c1"># mkae sure walkab</span>
</span></span><span class="line"><span class="cl">            <span class="n">mapflag</span> <span class="o">=</span> <span class="nb">map</span><span class="p">[</span><span class="n">current_node</span><span class="o">.</span><span class="n">position</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">current_node</span><span class="o">.</span><span class="n">position</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span> <span class="o">!=</span> <span class="nb">map</span><span class="p">[</span><span class="n">node_pos</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">node_pos</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span>
</span></span><span class="line"><span class="cl">            <span class="n">slopeflag1</span> <span class="o">=</span> <span class="n">slope</span><span class="p">[</span><span class="n">node_pos</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">node_pos</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span> <span class="o">==</span> <span class="mi">0</span>  <span class="ow">or</span> <span class="n">slope</span><span class="p">[</span><span class="n">current_node</span><span class="o">.</span><span class="n">position</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">current_node</span><span class="o">.</span><span class="n">position</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span> <span class="o">==</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">            <span class="n">slpopeflag2</span> <span class="o">=</span> <span class="n">slope</span><span class="p">[</span><span class="n">node_pos</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">node_pos</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span> <span class="o">!=</span> <span class="n">slope</span><span class="p">[</span><span class="n">current_node</span><span class="o">.</span><span class="n">position</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">current_node</span><span class="o">.</span><span class="n">position</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span>
</span></span><span class="line"><span class="cl">            
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">mapflag</span> <span class="ow">and</span> <span class="p">(</span><span class="n">slopeflag1</span> <span class="ow">or</span> <span class="n">slpopeflag2</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">                <span class="k">continue</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="c1"># we need creat node first to find out if it is in the openlist or closed list</span>
</span></span><span class="line"><span class="cl">            <span class="n">new_node</span> <span class="o">=</span> <span class="n">node</span><span class="p">(</span><span class="n">current_node</span><span class="p">,</span> <span class="n">node_pos</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">children</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">new_node</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1"># loop those children</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># using the __eq__ to judge if it&#39;s already traveled.</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">child</span> <span class="ow">in</span> <span class="n">children</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">child</span> <span class="ow">in</span> <span class="n">close_list</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="k">continue</span>
</span></span><span class="line"><span class="cl">            
</span></span><span class="line"><span class="cl">            <span class="c1"># create f,g,h for the legal child</span>
</span></span><span class="line"><span class="cl">            <span class="n">child</span><span class="o">.</span><span class="n">g</span> <span class="o">=</span> <span class="n">current_node</span><span class="o">.</span><span class="n">g</span> <span class="o">+</span> <span class="mi">1</span> 
</span></span><span class="line"><span class="cl">            <span class="n">child</span><span class="o">.</span><span class="n">h</span> <span class="o">=</span> <span class="n">manhattan</span><span class="p">(</span><span class="n">child</span><span class="o">.</span><span class="n">position</span><span class="p">,</span> <span class="n">end_node</span><span class="o">.</span><span class="n">position</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">child</span><span class="o">.</span><span class="n">f</span> <span class="o">=</span> <span class="n">child</span><span class="o">.</span><span class="n">g</span> <span class="o">+</span> <span class="n">child</span><span class="o">.</span><span class="n">f</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="c1"># if the child is already in the open list, compare it</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">child</span> <span class="ow">in</span> <span class="n">open_list</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="n">open_index</span> <span class="o">=</span> <span class="n">open_list</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="n">child</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="n">open_node</span> <span class="o">=</span> <span class="n">open_list</span><span class="p">[</span><span class="n">open_index</span><span class="p">]</span> 
</span></span><span class="line"><span class="cl">                <span class="k">if</span> <span class="n">child</span><span class="o">.</span><span class="n">g</span> <span class="o">&gt;</span> <span class="n">open_node</span><span class="o">.</span><span class="n">g</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                    <span class="k">continue</span>
</span></span><span class="line"><span class="cl">                <span class="n">open_list</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="n">open_index</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="c1"># if it is not in the open/closelist or better than that in open list, we add it.</span>
</span></span><span class="line"><span class="cl">            <span class="n">open_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">child</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script>]]></content:encoded>
    </item>
    <item>
      <title>Windows Configuration01 WSL2</title>
      <link>https://aikenh.cn/posts/wsl2/</link>
      <pubDate>Tue, 28 Sep 2021 02:17:39 +0000</pubDate>
      <guid>https://aikenh.cn/posts/wsl2/</guid>
      <description>init and set up WSL2</description>
      <content:encoded><![CDATA[<p>WSL（Windows Subsystem Linux） 将 Linux 环境部署在 Windows 中，Linux 环境在补全了 Windows 开发上的不足之外（Bash 等），还有以下的几个特性极大的便利开发和日常使用，因此强烈推荐启用并安装。</p>
<ul>
<li>win11 中 wsl2 已经支持相应主机的 cuda，便利了机器学习的开发；</li>
<li>子系统中通过/mnt 挂载了 windows 的磁盘，可以通过子系统访问和管理 windows 环境；</li>
<li>windows 资源管理器可访问和管理子系统中的文件</li>
<li>支持 windows 打开子系统中的 GUI 应用</li>
</ul>
<p>无论是将 windows 和 linux 分别作为日常和开发的环境来隔离，还是两个协同去做开发和日常，都是一个比较不错的选择，下面就介绍一下如何安装和使用 WSL2。</p>
<ul>
<li>开始之前可以参考 <a href="">windows terminal</a>
 安装一下这个官方的终端模拟器，在 windows 上的表现是比较优秀的</li>
<li>如果是考虑在 windows 环境开发的话，也可以参考这个[windows]，里面有我个人推荐的一些应用。</li>
</ul>
<h2 id="启用并安装-wsl2">启用并安装 WSL2</h2>
<p>安装和启用 WSL2 需要在 windows 的服务中勾选 Hyper-V 和 Windows Subsystem Linux 支持两个选项，具体操作如下：</p>
<ol>
<li>Win + S 搜索 &ldquo;功能&rdquo;，打开启用或关闭 windows 功能</li>
<li>启用对应功能，功能安装完毕后即可

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230305091044.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230305091044.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230305091044.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>


<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230305091150.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230305091150.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230305091150.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</li>
<li>安装 linux 发行版可以在 windows store 安装，也可以通过如下的命令进行安装：</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 列出对应的发行版</span>
</span></span><span class="line"><span class="cl"><span class="n">wsl</span> <span class="n">-l</span> <span class="n">-o</span>
</span></span><span class="line"><span class="cl"><span class="c"># 选择相应的发行版进行安装</span>
</span></span><span class="line"><span class="cl"><span class="n">wsl</span> <span class="p">-</span><span class="n">-install</span> <span class="n">-d</span> <span class="p">&lt;</span><span class="n">Distribution</span> <span class="n">Name</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="c"># 如果当前的WSL是1版本，更新到2</span>
</span></span><span class="line"><span class="cl"><span class="n">wsl</span> <span class="n">-l</span> <span class="n">-v</span>
</span></span><span class="line"><span class="cl"><span class="n">wsl</span> <span class="p">-</span><span class="n">-set-default-version</span> <span class="mf">2</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>安装完发行版之后，WindowsTerminal 中应该会自动出现其配置文件，如果没有出现也不要紧，可以先迁移其存储位置后再添加配置文件。</p>
<h2 id="mount-and-move">Mount And Move</h2>
<p><strong>WSL 的默认存储路径</strong>：<code>%LOCALAPPDATA%/packages/c......./local_state</code> 搜索 Ubuntu 文件夹</p>
<p>而通常 windows 都会有分区，如果是 C 盘较小的（建议是可以不用分区），可以修改 WSL 的默认存储路径，将磁盘挂载在别的地方，操作如下：</p>
<p>首先关闭对应的 wsl 服务，并查看关闭的状态：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">wsl</span> <span class="p">-</span><span class="n">-shutdown</span>
</span></span><span class="line"><span class="cl"><span class="n">wsl</span> <span class="n">-l</span> <span class="n">-v</span> <span class="c"># 查看状态</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>确认已经关闭后我们可以将该子系统文件导出，并将原有的系统注销删除</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 导出wsl2 system； docker-desktop &amp; docker-desktop-data</span>
</span></span><span class="line"><span class="cl"><span class="c"># 导出系统 wsl --export &lt;DistroName&gt; &lt;PathToTarArchive&gt;</span>
</span></span><span class="line"><span class="cl"><span class="n">wsl</span> <span class="p">-</span><span class="n">-export</span> <span class="n">Ubuntu</span><span class="p">-</span><span class="mf">20.04</span> <span class="n">E:</span><span class="p">\</span><span class="n">WSLWorkspace</span><span class="p">\</span><span class="n">ubuntu</span><span class="p">.</span><span class="py">tar</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 删除（注销）系统</span>
</span></span><span class="line"><span class="cl"><span class="n">wsl</span> <span class="p">-</span><span class="n">-unregister</span> <span class="n">Ubuntu</span><span class="p">-</span><span class="mf">20.04</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>最后在我们希望的地方重新注册该系统：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># 导入系统到指定的新位置(使用新路径导入新系统)</span>
</span></span><span class="line"><span class="cl"><span class="n">wsl</span> <span class="p">-</span><span class="n">-import</span> <span class="n">Ubuntu</span><span class="p">-</span><span class="mf">20.04</span> <span class="n">E:</span><span class="p">\</span><span class="n">WSLWorkspace</span> <span class="n">E:</span><span class="p">\</span><span class="n">WSLWorkspace</span><span class="p">\</span><span class="n">ubuntu</span><span class="p">.</span><span class="n">tar</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>通常来说，wsl 会自动为系统生成配置文件，这里在 terminal 中可能会出现两个 ubuntu 的 unid，那么我们就把第一个配置文件删掉，然后修改新的配置文件为（主要是在后面添加-u user_name）在指定启动的用户：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">&lt;...wsl.exe&gt; -d ubuntu -u &lt;user_name&gt;</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>or 修改注册表，可以参考以下的方法： <a href="https://www.vrunion.work/wsl-2-%E7%B3%BB%E7%BB%9F%E8%BF%81%E7%A7%BB%E5%88%B0%E9%9D%9E%E7%B3%BB%E7%BB%9F%E7%9B%98" target="_blank" rel="noopener">wsl2系统迁移到非系统盘</a>
</p>
<p>or 尝试，但是注意这种方式就不急着注销系统，因为他可能会重新安装在 C 盘，所以最后在注销。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">ubuntu2204 config --default-user &lt;user_name&gt;</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>删除多余的所有 tar，over</p>
<h3 id="dockerbased-on-wsl2">Docker（based on wsl2）</h3>
<p>基于 WSL2 安装的 Docker 也能用这种方式迁移相应的存储地点。就仅给出大概的操作流程，不在赘述。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># export</span>
</span></span><span class="line"><span class="cl"><span class="n">wsl</span> <span class="p">-</span><span class="n">-export</span> <span class="nb">docker-desktop</span><span class="n">-data</span> <span class="s2">&#34;D:\docker\docker-desktop-data.tar&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">wsl</span> <span class="p">-</span><span class="n">-export</span> <span class="nb">docker-desktop</span> <span class="s2">&#34;D:\docker\docker-desktop.tar&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># unresiester</span>
</span></span><span class="line"><span class="cl"><span class="c"># import </span>
</span></span><span class="line"><span class="cl"><span class="c"># restart</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="ssh">SSH</h2>
<p><a href="https://www.jianshu.com/p/3e2b7252b4b8" target="_blank" rel="noopener">wsl2启用SSH</a>
，ssh功能应该默认是启用的，如果ssh没有启用的话</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>sh</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">vim /etc/ssh/sshd_config</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>修改如下的几个配置</p>
<blockquote>
<p>Port = 22 去掉这行的 <code>#</code>，代表启用端口号 22
ListenAddress 0.0.0.0 去掉这行的#，代表监听所有地址
PasswordAuthentication yes，将这行的no改成yes，代表支持账号密码形式的登录</p>
</blockquote>
<p>重启服务</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo service ssh restart</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>此时还不能支持root用户密码登录,默认情况下，root用户只支持用RSA登录，但是可以修改配置的,切换到root用户打开SSH的配置文件</p>
<p>找到行<code>PermitRootLogin prohibit-password</code>保留这行的#，这意味着：允许root登录，但是禁止root用密码登录，所以这行要注释掉。
需要添加一行:</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>powershell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">PermitRootLogin</span> <span class="n">yes</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>剩下的其余配置按照<code>Linux</code>文档进行文件的配置</p>
<h2 id="proxy">PROXY</h2>
<h3 id="update">Update</h3>
<p>由于 WSL 2 中许多 CLI 工具都需要额外的进行代理设置，还有一些代码中也需要指定代理，令人不厌其烦，因此这里更新对于诸多 CLI 的额外设置。</p>
<p>参考资料（从前到后）：</p>
<ul>
<li><a href="https://blog.skk.moe/post/enable-proxy-on-ubuntu/" target="_blank" rel="noopener">Ubuntu「一键」设置代理 | Sukka&rsquo;s Blog (skk.moe)</a>
</li>
<li><a href="https://cat.ms/posts/wsl2-network-tricks/" target="_blank" rel="noopener">WSL2 的一些网络访问问题 | Artin&rsquo;s Blog (cat.ms)</a>
</li>
<li><a href="https://docs.cfw.lbyczf.com/contents/tun.html#windows" target="_blank" rel="noopener">TUN 模式 | Clash for Windows</a>
</li>
<li><a href="https://www.sulinehk.com/post/wsl-development-environment-proxy-settings/" target="_blank" rel="noopener">WSL 开发环境代理设置 - sulinehk&rsquo;s blog </a>
</li>
<li><a href="https://www.kiritoghy.cn/archives/wsl2pei-zhi-dai-li" target="_blank" rel="noopener">WSL2 配置代理 (kiritoghy.cn)</a>
</li>
</ul>
<p>推荐）<strong>通用方案</strong>：使用 Clash 的 TUN 模式，该方案会设置一个虚拟网卡，自动接管该方案设置完毕后无需配置 WSL 中任意 CLI 的代理。</p>
<blockquote>
<p>首先基于 server 旁边的地球按钮安装需要的依赖，安装完后就可以打开 tun 模式。</p>
</blockquote>
<p>备选）<strong>基础方案</strong>：使用脚本设置各个常用 CLI 的代理，需要设置代理的主要有以下这些：npm, yarn 等专用软件。</p>
<blockquote>
<p>wget 和 curl 这种使用的是全局的代理，所以不需要额外的设置，
但是像 npm 之类的专有软件一般有命令或者对应的配置文件；</p>
</blockquote>
<p>基于参考资料，个人基于需求进行修改，提供脚本如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>除了上述文章提到的这些，还有一个很容易遇到的问题就是 pip 的安装问题，设置 pip 的代理的方式有以下几种：</p>
<ul>
<li>使用 pip 的 <code>--proxy</code> 选项设置代理：<code>pip install libname --proxy http://127.0.0.1:7890</code></li>
<li>直接编辑pip的配置文件<code>pip.ini</code>，在其中的<code>[global]</code>下面添上一行<code>proxy = http://127.0.0.1:7890</code></li>
<li>使用 pip 的 <code>config</code> 命令来写配置文件：<code>pip config set global.proxy http://127.0.0.1:7890</code></li>
</ul>
<p>参考文献：<a href="https://codeantenna.com/a/pAOz55u5Px" target="_blank" rel="noopener">pip：ProxyError(‘Cannot connect to proxy. - CodeAntenna</a>
</p>
<h3 id="basic">Basic</h3>
<p>set the proxy for the WSL from windows, so we can update the packages ez.</p>
<ol>
<li>首先获取windows IP:</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">cat /etc/resolv.conf<span class="p">|</span>grep nameserver<span class="p">|</span>awk <span class="s1">&#39;{print $2}&#39;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 假设获取的windows ip 为170.20.0.1</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ol start="2">
<li>查看代理软件的端口设置，开启局域网 LAN 链接，开启<a href="https://blog.csdn.net/nick_young_qu/article/details/113709768" target="_blank" rel="noopener">防火墙</a>
</li>
</ol>
<ul>
<li>添加入站规则 -&gt; 新建规则</li>
<li>类型：自定义</li>
<li>程序：所有程序</li>
<li>协议和端口：默认</li>
<li>作用域：
<ul>
<li>本地为任何 ip</li>
<li>远程为下列 IP，把 WSL2 获取到的 ip 添加进去（比如上面就是 172.20.0.0/20）（掩码一般是 20 位）</li>
</ul>
</li>
<li>操作：允许链接</li>
<li>配置文件：三个全选</li>
<li>名称：自定义</li>
</ul>
<ol start="3">
<li>Clash 开启 LAN 和端口,</li>
<li>WSL2 中设置代理</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>shell</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">https_proxy</span><span class="o">=</span>172.20.0.1:8890
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">http_proxy</span><span class="o">=</span>172.20.0.1:8890</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>Reference</strong>： <a href="https://gray-ice.com/2021/10/04/WSL2%E4%BD%BF%E7%94%A8Windows%E4%B8%8A%E7%9A%84%E4%BB%A3%E7%90%86%E8%BD%AF%E4%BB%B6/" target="_blank" rel="noopener">proxy配置参考</a>
</p>
<p>这里提供一下 WSL 的代理设置脚本</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># show and set proxy for WSL</span>
</span></span><span class="line"><span class="cl"><span class="k">function</span> GetHostIp<span class="o">(){</span>
</span></span><span class="line"><span class="cl">  <span class="nv">ip</span><span class="o">=</span><span class="k">$(</span>cat /etc/resolv.conf<span class="p">|</span>grep nameserver<span class="p">|</span>awk <span class="s1">&#39;{print $2}&#39;</span><span class="k">)</span>
</span></span><span class="line"><span class="cl">  <span class="nb">echo</span> <span class="s2">&#34;the host ip is: </span><span class="nv">$ip</span><span class="s2">, then we ping it to test fireware&#34;</span>
</span></span><span class="line"><span class="cl">  ping <span class="nv">$ip</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">function</span> SetProxy<span class="o">(){</span>
</span></span><span class="line"><span class="cl">  <span class="nv">ip</span><span class="o">=</span><span class="k">$(</span>cat /etc/resolv.conf<span class="p">|</span>grep nameserver<span class="p">|</span>awk <span class="s1">&#39;{print $2}&#39;</span><span class="k">)</span>
</span></span><span class="line"><span class="cl">  <span class="nb">export</span> <span class="nv">http_proxy</span><span class="o">=</span>http://<span class="nv">$ip</span>:8890
</span></span><span class="line"><span class="cl">  <span class="nb">export</span> <span class="nv">https_proxy</span><span class="o">=</span>https://<span class="nv">$ip</span>:8890
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">function</span> unsetProxy<span class="o">(){</span>
</span></span><span class="line"><span class="cl">  <span class="nb">unset</span> http_proxy
</span></span><span class="line"><span class="cl">  <span class="nb">unset</span> https_proxy
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">getip</span><span class="o">=</span>GetHostIp
</span></span><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">proxyon</span><span class="o">=</span>SetProxy
</span></span><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">proxyoff</span><span class="o">=</span>unsetProxy</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="setting">SETTING</h2>
<p>WSL在Windows Terminal的启动目录设置</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>json</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="err">//wsl$/Ubuntu</span><span class="mf">-20.04</span><span class="err">/home/aikenhong</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="vmmem-内存占用问题">Vmmem 内存占用问题</h3>
<blockquote>
<p>Windows 使用 Wsl2 &amp; 基于 Wsl2 的 Docker 时会发现 Vmmem 占用了系统大量的内存（15g/32g），且同时 Docker Dashboard 和 Linux 中的 Top 命令都显示占用并不高。</p>
</blockquote>
<p>Vmmem 进程是 Windows 系统为 WSL2 系统预留的虚拟进程，为 WSL2 向系统申请内存和 CPU 资源，即使在 WSL2 并不需要的时候也会保留大量的内存，其默认消耗总内存的50% (20175之前的版本则是80%) 或者 8G，选择其中较小的一个执行。</p>
<ul>
<li>如果需要使用内存且无需 WSL2 时可以使用 <code>wsl --shutdown</code> 命令关闭 WSL2；</li>
</ul>
<p>进入用户文件夹后，新建 or 打开 <code>.wslconfig</code> 文件</p>
<ul>
<li>powershell <code>cd ~</code></li>
<li>WIN+R <code>%UserProfile%</code></li>
<li>资源管理器 %UserProfile%</li>
</ul>
<p>在其中可以编辑 wsl2 的 memory 选项，手动其内存使用的上限：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>txt</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl"># Settings apply across all Linux distros running on WSL 2 
</span></span><span class="line"><span class="cl">[wsl2] 
</span></span><span class="line"><span class="cl">memory=8GB </span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>重启 WSL 或者直接重启电脑即可。</p>
]]></content:encoded>
    </item>
    <item>
      <title>Windows Configuration00 系统初始配置</title>
      <link>https://aikenh.cn/posts/windows/</link>
      <pubDate>Tue, 28 Sep 2021 02:16:26 +0000</pubDate>
      <guid>https://aikenh.cn/posts/windows/</guid>
      <description>Some Special tips for Windows</description>
      <content:encoded><![CDATA[<p>@AikenHong 2020</p>
<p>本文介绍个人的 windows 开发环境搭建（包括一些环境安装、功能启用）以及一些使用的小 tips。</p>
<h2 id="软件推荐">软件推荐</h2>
<p>Windows 的账号同步功能善用，减少在环境迁移的时候对浏览器插件和 Vscode 插件的繁琐同步步骤。</p>
<p>同时对 Onedrive 和外接硬盘的应用可以很好的减轻备份的负担，在网络环境对 Onedrive 友好的时候还是推荐使用，在 Mac 和 Windows 上都有一个比较好的体验。</p>
<h3 id="一些基础的软件">一些基础的软件</h3>
<table>
  <thead>
      <tr>
          <th>Software</th>
          <th>Type</th>
          <th>Free? &amp; source</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Powertorys</td>
          <td>system enhance</td>
          <td>y &amp; github</td>
      </tr>
      <tr>
          <td>Translucent</td>
          <td>beautify</td>
          <td>y &amp; Microsoft Store</td>
      </tr>
      <tr>
          <td>Snipaste</td>
          <td>system enhance</td>
          <td>y &amp; offical site</td>
      </tr>
      <tr>
          <td>Clash for windows</td>
          <td>proxy</td>
          <td>y &amp; github</td>
      </tr>
      <tr>
          <td>everything</td>
          <td>search-file</td>
          <td>y &amp; offical site</td>
      </tr>
      <tr>
          <td>Potplayer</td>
          <td>Player</td>
          <td>y &amp; offical site</td>
      </tr>
      <tr>
          <td>Twinkle Tray</td>
          <td>screen control</td>
          <td>y &amp; offical site</td>
      </tr>
      <tr>
          <td>7 zip</td>
          <td>system enhanc</td>
          <td>y &amp; offical site</td>
      </tr>
      <tr>
          <td>Zerotier</td>
          <td>NAT</td>
          <td>y &amp; offical site</td>
      </tr>
      <tr>
          <td>Nerd Font</td>
          <td>Font</td>
          <td>y &amp; offical site</td>
      </tr>
      <tr>
          <td>Wallpaper Engine</td>
          <td>beautify</td>
          <td>n &amp; steam</td>
      </tr>
      <tr>
          <td>MyDockerFinder</td>
          <td>beautify</td>
          <td>n &amp; steam</td>
      </tr>
      <tr>
          <td>IDM</td>
          <td>Download</td>
          <td>n &amp; offical site</td>
      </tr>
  </tbody>
</table>
<h3 id="开发工具">开发工具</h3>
<table>
  <thead>
      <tr>
          <th>Software</th>
          <th>Type</th>
          <th>Free? &amp; source</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Windows Terminal</td>
          <td>Terminal Simulator</td>
          <td>y &amp; Microsoft Store</td>
      </tr>
      <tr>
          <td>Powershell 7</td>
          <td>Shell</td>
          <td>y &amp; Github</td>
      </tr>
      <tr>
          <td>VsCode</td>
          <td>Editor</td>
          <td>y &amp; Offical Site</td>
      </tr>
      <tr>
          <td>Visual Studio</td>
          <td>IDE</td>
          <td>y &amp; Offical Site</td>
      </tr>
      <tr>
          <td>Interllij IDEA</td>
          <td>IDE</td>
          <td>n &amp; Offical Site</td>
      </tr>
      <tr>
          <td>Git</td>
          <td>-</td>
          <td>-</td>
      </tr>
      <tr>
          <td>Nodejs</td>
          <td>-</td>
          <td>-</td>
      </tr>
      <tr>
          <td>Anaconda</td>
          <td>-</td>
          <td>-</td>
      </tr>
  </tbody>
</table>
<h3 id="文档编写">文档编写</h3>
<table>
  <thead>
      <tr>
          <th>Software</th>
          <th>Type</th>
          <th>Free &amp; Source</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Obsidian</td>
          <td>Markdown Editor</td>
          <td>y &amp; offical-site</td>
      </tr>
      <tr>
          <td>Typora</td>
          <td>Markdown Editor</td>
          <td>n &amp; offical-site</td>
      </tr>
      <tr>
          <td>Picgo</td>
          <td>Image Upload</td>
          <td>y &amp; offical-site</td>
      </tr>
      <tr>
          <td>CopyTranslate</td>
          <td>Translate</td>
          <td>y &amp; offical-site</td>
      </tr>
      <tr>
          <td>Mathpix Snipping Tool</td>
          <td>Latex Formulate</td>
          <td>- &amp; offical-site</td>
      </tr>
  </tbody>
</table>
<h3 id="daily">Daily</h3>
<table>
  <thead>
      <tr>
          <th>Software</th>
          <th>Free &amp; Source</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Office</td>
          <td>n &amp; offical-site</td>
      </tr>
      <tr>
          <td>Tim</td>
          <td>y  &amp; offical-site</td>
      </tr>
      <tr>
          <td>WeChat</td>
          <td>y  &amp; offical-site</td>
      </tr>
      <tr>
          <td>OneDrive</td>
          <td>y  &amp; offical-site</td>
      </tr>
      <tr>
          <td>Steam</td>
          <td>-  &amp; offical-site</td>
      </tr>
      <tr>
          <td>Epic</td>
          <td>-  &amp; offical-site</td>
      </tr>
      <tr>
          <td>yy</td>
          <td>y  &amp; offical-site</td>
      </tr>
      <tr>
          <td>uu</td>
          <td>n  &amp; offical-site</td>
      </tr>
      <tr>
          <td>网易云</td>
          <td>y   &amp; offical-site</td>
      </tr>
  </tbody>
</table>
<h2 id="开发环境配置">开发环境配置</h2>
<ul>
<li><strong>安装 python</strong>：直接去 <a href="https://www.anaconda.com/" target="_blank" rel="noopener">https://www.anaconda.com</a>
 下载，安装的时候使其添加到路径中</li>
<li><strong>安装 Node</strong>：windows 直接去 <a href="https://nodejs.org/en/" target="_blank" rel="noopener">nodejs</a>
 官网下载安装，详细文档请参考<a href="https://aikenh.cn/cn/Nodes/" target="_blank" rel="noopener">Node Version Manage - AikenH Blogs</a>
</li>
<li>安装 Window Terminal：
<ul>
<li>Win11 中自带</li>
<li>Win10 可以在 windows store 中安装，也可以去 Github 界面安装</li>
<li>配置请参考 <a href="">WindowsTerminal - AIkenH Blogs</a>
</li>
</ul>
</li>
</ul>
<h3 id="安装-powershell7">安装 PowerShell7</h3>
<p>该部分安装 PS7 并在 WindowsTerminal 中设置其配置文件：</p>
<p><strong>安装部分</strong>：在 PowerShell 的 Github Releases 界面下载 msi 版本 <a href="https://github.com/PowerShell/PowerShell" target="_blank" rel="noopener">PowerShell/PowerShell: PowerShell for every system! (github.com)</a>
 直接安装即可，自己选择安装位置。</p>
<p><strong>配置</strong>参考文档：<a href="">Powershell- Aikenh Blogs</a>
</p>
<h3 id="启用-wsl2">启用 WSL2</h3>
<p>这里简单介绍如何启用和安装 WSL2，后续相关的配置等信息参考 <a href="">WSl2 - Aikenh Blogs</a>
;</p>
<p>安装和启用 WSL2 需要在 windows 的服务中勾选 Hyper-V 和 Windows Subsystem Linux 支持两个选项，具体操作如下：</p>
<ol>
<li>Win + S 搜索 &ldquo;功能&rdquo;，打开启用或关闭 windows 功能</li>
<li>启用对应功能，功能安装完毕后即可

<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230305091044.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230305091044.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230305091044.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>


<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230305091150.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230305091150.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230305091150.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</li>
<li>在 windows store 中安装需要的 Linux 发行版</li>
<li>参考上述所说博文迁移存储位置，配置 windows terminal 等。</li>
</ol>
<h2 id="其他操作">其他操作</h2>
<h3 id="粘滞键关闭问题">粘滞键关闭问题</h3>
<p>Sometimes, we could not disable the sticky key which enable for some reason. We could only disable this by click shift 5 time in <strong>LAPTOP ORIGIN KEYBOARD</strong> other than the <strong>EXTERNAL KEYBOARD</strong>.</p>
<h3 id="百度网盘倍速播放">百度网盘倍速播放</h3>
<p>百度网盘的网页版倍速播放的技巧：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">videojs.getPlayers(&#34;video-player&#34;).html5player.tech_.setPlaybackRate(2)</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="office-恢复自动保存的文件">Office 恢复自动保存的文件</h3>
<ul>
<li>首先在设置（选项）界面找到自动保存的 asd 文件的地址</li>
<li>在信息-管理文档中选择 ASD 进行对文档的恢复</li>
</ul>
<h3 id="install-nerd-font">Install Nerd Font</h3>
<p>在 <a href="https://www.nerdfonts.com/" target="_blank" rel="noopener">Nerd Fonts</a>
 中下载字体后直接右键安装即可，推荐安装，无论是进行编程开发的时候还是针对命令行的美化，或者是 windows terminal 的体验，都是一个必不可少的环节。</p>
<h3 id="clash-设置微软相关应用不启用">Clash 设置微软相关应用不启用</h3>
<p>在主界面的 UWP Loopback 中选中启用代理后出现问题的应用如商店和便笺等</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230325090131.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230325090131.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230325090131.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230325090158.png">
    <img alt="image.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230325090158.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/3070PC/20230325090158.png" style="display: block; margin: 0 auto;"
      alt="image.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h3 id="onedrive-路径切换">OneDrive 路径切换</h3>
<p>将 OneDrive 设置中的账户选项卡里取消链接此电脑，然后将 OneDrive 的文件夹移动到新的存储位置，最后重新设置 OneDrive，直到到达显示文件夹位置的窗口，选择更改位置，然后选择新的存储位置即可。</p>
<p>文件夹的默认位置在：<code>c:\user\&lt;username&gt;\OneDrive</code></p>
<h3 id="hevc-解码器下载">Hevc 解码器下载</h3>
<p>windows 下查看 heic 图片或者一些视频文件的时候会需要 hevc 解码器，该解码器可以从 <a href="https://hevc-video-extensions-from-device-manufacturer.cn.uptodown.com/windows" target="_blank" rel="noopener">Uptodownload</a>
 免费下载，无需购买 Microsoft Store 里面的 7 块钱。</p>
]]></content:encoded>
    </item>
    <item>
      <title>基于 Gitbook 发布笔记</title>
      <link>https://aikenh.cn/posts/gitbook/</link>
      <pubDate>Sun, 26 Sep 2021 15:36:25 +0000</pubDate>
      <guid>https://aikenh.cn/posts/gitbook/</guid>
      <description>Build your Gitbook</description>
      <content:encoded><![CDATA[<p>Gitbook命令行工具，基于Markdown编写文档，后续基于Github发布该Blog</p>
<p>笔记的构建流程：</p>
<h2 id="chapter1-install">Chapter1 Install</h2>
<p>安装<code>Gitbook</code>之前我们需要安装<code>node.js</code>和<code>npm</code>的依赖，使用<code>npm</code>安装<code>gitbook</code></p>
<ul>
<li>
<p>首先安装Install Nodejs，Npm</p>
<p>Windows：<a href="https://nodejs.org/zh-cn/download/" target="_blank" rel="noopener">Node.js (nodejs.org)</a>
</p>
<p>Linux:</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># add &amp; update apt source before install nodejs.</span>
</span></span><span class="line"><span class="cl">curl -sL https://deb.nodesource.com/setup_14.x <span class="p">|</span> sudo -E bash -
</span></span><span class="line"><span class="cl">sudo apt-get update
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># install nodejs after that.</span>
</span></span><span class="line"><span class="cl">sudo apt-get install -y nodejs</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>然后安装gitbook</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm install gitbook-cli -g 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">gitbook fetch beta <span class="c1"># 安装历史版本</span>
</span></span><span class="line"><span class="cl">gitbook ls-remote <span class="c1"># 列举可以下载的版本</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>检查Gitbook版本</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">gitbook -V</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
</ul>
<h3 id="安装gitbook插件">安装Gitbook插件</h3>
<p>安装插件主要有两种方式：一种是直接通过book和gitbook的安装来实现，另一种是基于Npm预先安装</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm install gitbook-plugin-PACKAGE</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>基于<strong>book</strong>的安装方式</p>
<p>插件和相关的配置在<code>book.json</code>中指定，关键词<code>plugins</code> &amp; <code>pluginsConfig</code>为对应的插件的配置信息</p>
<p>添加插件通过修改<code>book.json</code>如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>json</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&#34;plugins&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;-summary&#34;</span><span class="p">,</span><span class="s2">&#34;-katex&#34;</span><span class="p">,</span><span class="s2">&#34;mathjax-pro&#34;</span><span class="p">,</span><span class="s2">&#34;anchor-navigation-ex-toc&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;search-plus&#34;</span><span class="p">,</span><span class="s2">&#34;-lunr&#34;</span><span class="p">,</span><span class="s2">&#34;-search&#34;</span><span class="p">,</span><span class="s2">&#34;splitter&#34;</span><span class="p">,</span><span class="s2">&#34;copy-code-button&#34;</span><span class="p">,</span><span class="s2">&#34;github&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;theme-comscore&#34;</span><span class="p">,</span><span class="s2">&#34;-latex-codecogs&#34;</span><span class="p">,</span><span class="s2">&#34;tbfed-pagefooter&#34;</span><span class="p">,</span><span class="s2">&#34;-expandable-chapters-small&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;-edit-link-plus&#34;</span><span class="p">,</span><span class="s2">&#34;expandable-chapters&#34;</span><span class="p">,</span><span class="s2">&#34;pageview-count&#34;</span><span class="p">,</span><span class="s2">&#34;-editlink&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;lightbox&#34;</span><span class="p">,</span><span class="s2">&#34;-highlight&#34;</span><span class="p">,</span><span class="s2">&#34;prism&#34;</span><span class="p">,</span><span class="s2">&#34;disqus&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>添加完新的插件配置之后，运行<code>gitbook install ./</code>来安装新的插件</p>
<p><a href="https://www.npmjs.com/package/gitbook-plugin-mathjax-pro" target="_blank" rel="noopener">gitbook-plugin-mathjax-pro - npm (npmjs.com)</a>
；<a href="https://github.com/PrismJS/prism-themes" target="_blank" rel="noopener">PrismJS/prism-themes: A wider selection of Prism themes (github.com)</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># gitbook-plugin-mathjax-pro 安装方式</span>
</span></span><span class="line"><span class="cl">npm install mathjax@2.7.7
</span></span><span class="line"><span class="cl">npm install gitbook-plugin-mathjax-pro
</span></span><span class="line"><span class="cl"><span class="c1"># and editor the book.json as below</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>json</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;author&#34;</span><span class="p">:</span> <span class="s2">&#34;AikenHong&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;Aiken&#39;s Blogs&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;language&#34;</span><span class="p">:</span> <span class="s2">&#34;zh-hans&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;plugins&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;-summary&#34;</span><span class="p">,</span><span class="s2">&#34;-katex&#34;</span><span class="p">,</span><span class="s2">&#34;mathjax-pro&#34;</span><span class="p">,</span><span class="s2">&#34;anchor-navigation-ex-toc&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;search-plus&#34;</span><span class="p">,</span><span class="s2">&#34;-lunr&#34;</span><span class="p">,</span><span class="s2">&#34;-search&#34;</span><span class="p">,</span><span class="s2">&#34;splitter&#34;</span><span class="p">,</span><span class="s2">&#34;copy-code-button&#34;</span><span class="p">,</span><span class="s2">&#34;github&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;theme-comscore&#34;</span><span class="p">,</span><span class="s2">&#34;-latex-codecogs&#34;</span><span class="p">,</span><span class="s2">&#34;tbfed-pagefooter&#34;</span><span class="p">,</span><span class="s2">&#34;-expandable-chapters-small&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;-edit-link-plus&#34;</span><span class="p">,</span><span class="s2">&#34;expandable-chapters&#34;</span><span class="p">,</span><span class="s2">&#34;pageview-count&#34;</span><span class="p">,</span><span class="s2">&#34;-editlink&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;lightbox&#34;</span><span class="p">,</span><span class="s2">&#34;-highlight&#34;</span><span class="p">,</span><span class="s2">&#34;prism&#34;</span><span class="p">,</span><span class="s2">&#34;disqus&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;pluginsConfig&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;insert-logo&#34;</span><span class="p">:{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;url&#34;</span><span class="p">:</span> <span class="s2">&#34;https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210927180958.png&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;style&#34;</span><span class="p">:</span> <span class="s2">&#34;background: none; max-height: 120px; min-height: 120px&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;github&#34;</span><span class="p">:{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;url&#34;</span><span class="p">:</span> <span class="s2">&#34;https://aikenh.github.io/about/&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;tbfed-pagefooter&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;copyright&#34;</span><span class="p">:</span><span class="s2">&#34;&amp;copy AikenHong&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;modify_label&#34;</span><span class="p">:</span> <span class="s2">&#34;该文件修订时间：&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;modify_format&#34;</span><span class="p">:</span> <span class="s2">&#34;YYYY-MM-DD HH:mm:ss&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;mathjax-pro&#34;</span><span class="p">:{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="s2">&#34;2.7.7&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;prism&#34;</span><span class="p">:{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;css&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;prismjs/themes/prism-tomorrow.css&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;lang&#34;</span><span class="p">:{</span>
</span></span><span class="line"><span class="cl">                <span class="nt">&#34;flow&#34;</span><span class="p">:</span> <span class="s2">&#34;typescript&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;disqus&#34;</span><span class="p">:{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;shortName&#34;</span><span class="p">:</span> <span class="s2">&#34;aikensdoc&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>安装Disqus的时候，要到Disqus官网进行账号注册，并安装个人评论的网站，记录唯一的个人标识符，然后再配置中引入即可；</p>
<p>使用prism代替</p>
<h2 id="chapter2-configure">Chapter2 Configure</h2>
<p><code>gitbook init</code>会初始化文件目录，文件夹会包含如下的结构：目录中的文件对应有如下的作用</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">.
</span></span><span class="line"><span class="cl">├── _book         <span class="c1"># 自动生成的html</span>
</span></span><span class="line"><span class="cl">├── book.json     <span class="c1"># 配置文件</span>
</span></span><span class="line"><span class="cl">├── README.md     <span class="c1"># 电子书的前言或者简介</span>
</span></span><span class="line"><span class="cl">├── SUMMARY.md    <span class="c1"># 电子书的目录</span>
</span></span><span class="line"><span class="cl">├── chapter-1/
</span></span><span class="line"><span class="cl"><span class="p">|</span>   ├── README.md <span class="c1"># 章节的描述</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span>   └── something.md
</span></span><span class="line"><span class="cl">└── chapter-2/ 
</span></span><span class="line"><span class="cl">    ├── README.md <span class="c1"># 章节的描述</span>
</span></span><span class="line"><span class="cl">    └── something.md</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>编辑对应的<code>SUMMARY</code>同时可以按照文件夹结构进行组织，基本的组织结构可以按照下面的来进行部署</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>markdown</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl"><span class="gh"># 概要
</span></span></span><span class="line"><span class="cl"><span class="gh"></span>
</span></span><span class="line"><span class="cl"><span class="k">*</span> [<span class="nt">卷 I</span>](<span class="na">part1/README.md</span>)
</span></span><span class="line"><span class="cl">    <span class="k">*</span> [<span class="nt">写作很棒</span>](<span class="na">part1/writing.md</span>)
</span></span><span class="line"><span class="cl">    <span class="k">*</span> [<span class="nt">GitBook很酷</span>](<span class="na">part1/gitbook.md</span>)
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl"><span class="k">*</span> [<span class="nt">卷 II</span>](<span class="na">part2/README.md</span>)
</span></span><span class="line"><span class="cl">    <span class="k">*</span> [<span class="nt">期待反馈</span>](<span class="na">part2/feedback_please.md</span>)
</span></span><span class="line"><span class="cl">    * [<span class="nt">更好的写作工具</span>](<span class="na">part2/better_tools.md</span>)</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="chapter3-deploy">Chapter3 Deploy</h2>
<p>在本地部署和运行一个样本书，设置gitbook的配置文件</p>
<h3 id="初始化">初始化</h3>
<p>将书籍创建到当前的目录或者指定的目录中</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">gitbook init
</span></span><span class="line"><span class="cl">gitbook init ./directory <span class="c1"># 在指定的目录中生成</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="构建">构建</h3>
<p>使用下面的命令会在当前目录下或者指定目录里生成<code>_book</code>目录，里面的内容是静态站点的资源文件：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">gitbook build</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="debugging">Debugging</h3>
<p>您可以使用选项 <code>--log=debug</code> 和 <code>--debug</code> 来获取更好的错误消息（使用堆栈跟踪）。例如：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">gitbook build ./ --log<span class="o">=</span>debug --debug</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="启动服务">启动服务</h3>
<p>使用下列服务在<a href="http://localhost:4000/" target="_blank" rel="noopener">LocalHost</a>
可以预览我们的的本地书籍</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">gitbook serve</span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="chapter4-publish">Chapter4 Publish</h2>
<p>希望可以不借助<code>gitbook</code>服务来可视化界面，全靠<code>git</code> &amp; <code>cmd</code> &amp; <code>github</code>来进行一系列操作，这样就能通过我的<code>onedrive</code>来进行比较好的统一管理</p>
<h3 id="托管到github-pages">托管到Github Pages</h3>
<p>optional: 创建username.github.io的个人repo,可以通过<a href="https://github.com/AikenH/aikenh.github.io" target="_blank" rel="noopener">jekyll</a>
来init该githubpage</p>
<ul>
<li>创建note&rsquo;s repo, 用来存储自己的所有Liture</li>
<li>调用<code>gitbook serve</code>之后将<code>_book</code>的文件推送到repo的gh-pages分支</li>
<li>就可以在下列的url中看到自己的文档：aikenh.github.io/REPONAME/</li>
<li>修改io文件夹中的_layout中的Default.html如下
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>html</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://aikenh.github.io/Docs/&#34;</span><span class="p">&gt;</span>Blog<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>bash</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># enter the right dir</span>
</span></span><span class="line"><span class="cl"><span class="c1"># we need to excute gitbook serve int terminal first</span>
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> _book
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># using condtional rules to control the update actions</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[</span> -d <span class="s2">&#34;.git&#34;</span> <span class="o">]</span><span class="p">;</span><span class="k">then</span>
</span></span><span class="line"><span class="cl">  <span class="nb">echo</span> <span class="s2">&#34;exist git files&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span>
</span></span><span class="line"><span class="cl">  git init
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># update those blogs using git</span>
</span></span><span class="line"><span class="cl">git add . 
</span></span><span class="line"><span class="cl">git commit -m <span class="s2">&#34;update those blogs&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;update the local git log&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># push the update to the remote repo</span>
</span></span><span class="line"><span class="cl">git remote add origin git@github.com:AikenH/Docs.git
</span></span><span class="line"><span class="cl">git push -f origin master:gh-pages
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;finish pushing files&#34;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="reference">Reference</h2>
<ul>
<li><a href="https://chrisniael.gitbooks.io/gitbook-documentation/content/github/index.html" target="_blank" rel="noopener">集成GitHub | GitBook文档（中文版） (gitbooks.io)</a>
</li>
<li><a href="https://www.cnblogs.com/mingyue5826/p/10307051.html#11-%e5%85%a8%e5%b1%80%e9%85%8d%e7%bd%ae" target="_blank" rel="noopener">GitBook插件整理 - book.json配置</a>
</li>
<li><a href="https://dunwu.gitbooks.io/gitbook-notes/content/GLOSSARY.html" target="_blank" rel="noopener">gitbook-notes (gitbooks.io)</a>
</li>
<li><a href="https://blog.cugxuan.cn/2018/12/03/Markdown/How-to-use-gitbook-elegantly/" target="_blank" rel="noopener">内含github部署资料</a>
</li>
<li><a href="https://pandao.github.io/editor.md/examples/katex.html" target="_blank" rel="noopener">Katex 测试验证</a>
</li>
<li><a href="https://github.com/julianxhokaxhiu/gitbook-plugin-summary#readme" target="_blank" rel="noopener">Gitbook-plugin-summary</a>
</li>
<li><a href="https://www.cnblogs.com/zhangjk1993/p/5066771.html#_label2_2" target="_blank" rel="noopener">实用配置及插件介绍</a>
</li>
<li><a href="https://www.cnblogs.com/snowdreams1006/p/10680684.html" target="_blank" rel="noopener">gitbook 入门教程之主题插件</a>
</li>
<li><a href="https://szdastone.github.io/posts/2019/01/4dd0f083.html" target="_blank" rel="noopener">Gitbook插件和主题</a>
</li>
<li><a href="https://www.jianshu.com/p/53fccf623f1c" target="_blank" rel="noopener">GitBook相关配置及优化</a>
</li>
<li><a href="https://www.cnblogs.com/phyger/p/14035937.html#Github_Pages_629" target="_blank" rel="noopener">打造完美写作系统：Gitbook+Github Pages+Github Actions - phyger - 博客园 (cnblogs.com)</a>
</li>
<li><a href="http://gitbook.zhangjikai.com/plugins.html#prsim" target="_blank" rel="noopener">插件</a>
</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>RL-DouZero</title>
      <link>https://aikenh.cn/posts/rl-douzero/</link>
      <pubDate>Tue, 06 Jul 2021 13:51:48 +0000</pubDate>
      <guid>https://aikenh.cn/posts/rl-douzero/</guid>
      <description>Mastering DouDizhu with Self-Play Deep Reinforcement Learning</description>
      <content:encoded><![CDATA[<p>Desc: GAME, RL
Finished?: Yes
Tags: Paper
URL1: <a href="https://arxiv.org/abs/2106.06135" target="_blank" rel="noopener">https://arxiv.org/abs/2106.06135</a>

URL2: <a href="https://github.com/kwai/DouZero" target="_blank" rel="noopener">https://github.com/kwai/DouZero</a>

URL3: <a href="https://github.com/datamllab/rlcard-showdown" target="_blank" rel="noopener">https://github.com/datamllab/rlcard-showdown</a>
）</p>
<p>使用蒙特卡洛方法进行自我对弈不断更新预测模型的方法，这实际上也是普通人对于强化学习如何在self-play中实现自我更新的最基础的想法把：
自我对弈（记录动作序列）- 用最终的胜负（价值）更新网络。</p>
<h2 id="算法的设计和思路">算法的设计和思路</h2>
<p>算法的目标是学习一个价值网路。网络的输入是当前状态和一个动作，输出是在当前状态做这个动作的期望收益（比如胜率）。简单来说，价值网络在每一步计算出哪种牌型赢的概率最大，然后选择最有可能赢的牌型。蒙特卡罗方法不断重复以下步骤来优化价值网络：</p>
<ul>
<li>用价值网络生成一场对局</li>
<li>记录下该对局中所有的状态、动作和最后的收益（胜率）</li>
<li>将每一对状态和动作作为网络输入，收益作为网络输出，用梯度下降对价值网络进行一次更新</li>
</ul>
<p>其实，所谓的蒙特卡罗方法就是一种随机模拟，即通过不断的重复实验来估计真实价值。</p>
<p>如下图所示，斗零采用一个价值神经网络，其输入是状态和动作，输出是价值。首先，过去的出牌用 LSTM 神经网络进行编码。然后 LSTM 的输出以及其他的表征被送入了 6 层全连接网络，最后输出价值。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911211016">
    <img alt="img" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911211016"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911211016" style="display: block; margin: 0 auto;"
      alt="img"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>系统训练的主要瓶颈在于模拟数据的生成，因为每一步出牌都要对神经网络做一次前向传播。斗零采用多演员（actor）的架构，在单个 GPU 服务器上，用了 45 个演员同时产生数据，最终数据被汇集到一个中央训练器进行训练。比较有趣的是，斗零并不需要太多的计算资源，仅仅需要一个普通的四卡 GPU 服务器就能达到不错的效果。这可以让大多数实验室轻松基于作者的代码做更多的尝试。</p>
<p>该方法的设计和实现上听起来都挺简单的，可以找个时间自己测试一下，玩一玩这个东西，对于我来说，看看他们怎么用这个lstm去进行历史编码的，以及在对transformer了解后，看看如何用transformer去替代这样的lstm是我这边的研究重点。</p>
<h2 id="蒙特卡洛方法存在的问题">蒙特卡洛方法存在的问题</h2>
<p>蒙特卡罗方法在强化学习领域中被大多数研究者忽视。学界普遍认为蒙特卡罗方法存在两个缺点：</p>
<ol>
<li>
<p>蒙特卡罗方法不能处理不完整的状态序列</p>
</li>
<li>
<p>蒙特卡罗方法有很大的方差，导致采样效率很低。</p>
</li>
</ol>
<p>但是斗地主中，可以产生转正的状态序列，同时很容易通过并行来采集大量的样本降低方差，主要是实现上简单，但是可能也是需要大量的数据把。</p>
<h2 id="蒙特卡洛方法在该任务上存在的优势">蒙特卡洛方法在该任务上存在的优势</h2>
<ul>
<li>很容易对动作进行编码。斗地主的动作与动作之前是有内在联系的。以三带一为例：如果智能体打出 KKK 带 3，并因为带牌带得好得到了奖励，那么其他的牌型的价值，例如 JJJ 带 3，也能得到一定的提高。这是由于神经网络对相似的输入会预测出相似的输出。动作编码对处理斗地主庞大而复杂的动作空间非常有帮助。智能体即使没有见过某个动作，也能通过其他动作对价值作出估计。</li>
<li>不受过度估计（over-estimation）的影响。最常用的基于价值的强化学习方法是 DQN。但众所周知，DQN 会受过度估计的影响，即 DQN 会倾向于将价值估计得偏高，并且这个问题在动作空间很大时会尤为明显。不同于 DQN，蒙特卡罗方法直接估计价值，因此不受过度估计影响。这一点在斗地主庞大的动作空间中非常适用。</li>
<li>蒙特卡罗方法在稀疏奖励的情况下可能具备一定优势。在斗地主中，奖励是稀疏的，玩家需要打完整场游戏才能知道输赢。DQN 的方法通过下一个状态的价值估计当前状态的价值。这意味着奖励需要一点一点地从最后一个状态向前传播，这可能导致 DQN 更慢收敛。与之相反，蒙特卡罗方法直接预测最后一个状态的奖励，不受稀疏奖励的影响。</li>
</ul>
<h2 id="reference">Reference</h2>
<p><a href="https://mp.weixin.qq.com/s/6EkEMkuer7wRVBSpWnIuJQ" target="_blank" rel="noopener">快手开源斗地主AI，入选ICML，能否干得过「冠军」柯洁？</a>
</p>
<p><a href="https://arxiv.org/abs/2106.06135" target="_blank" rel="noopener">DouZero: Mastering DouDizhu with Self-Play Deep Reinforcement Learning</a>
</p>
<p><a href="https://github.com/kwai/DouZero" target="_blank" rel="noopener">GitHub - kwai/DouZero: [ICML 2021] DouZero: Mastering DouDizhu with Self-Play Deep Reinforcement Learning | 斗地主AI</a>
</p>
]]></content:encoded>
    </item>
    <item>
      <title>Leetcode 题型和框架代码总结</title>
      <link>https://aikenh.cn/posts/intview_%E7%AC%94%E8%AF%95%E9%A2%98%E5%9E%8B%E5%92%8C%E6%A1%86%E6%9E%B6%E6%80%BB%E7%BB%93/</link>
      <pubDate>Tue, 29 Jun 2021 10:18:47 +0000</pubDate>
      <guid>https://aikenh.cn/posts/intview_%E7%AC%94%E8%AF%95%E9%A2%98%E5%9E%8B%E5%92%8C%E6%A1%86%E6%9E%B6%E6%80%BB%E7%BB%93/</guid>
      <description>conclusion for leetcode</description>
      <content:encoded><![CDATA[<head>
    
    <script src="https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/crypto-js/3.1.9-1/crypto-js.js"></script>
</head>





<div class="hugo-encryptor-container">
  <div class="hugo-encryptor-prompt">
    
      <p>文章的部分内容被密码保护：</p>
    
  </div>
  <div class="hugo-encryptor-form">
    <input
      class="hugo-encryptor-input"
      placeholder='请输入密码'
    />
    <input
      class="hugo-encryptor-button"
      type="button"
      value='CLICK'
      onclick="_click_handler(this)"
    />
  </div>
  <div
    class="hugo-encryptor-cipher-text"
    data-password="aikenhong_blog"
    style="display: none;"
  >
    <span style="display: none;">--- DON'T MODIFY THIS LINE ---</span>
    <p>@Aiken 2021 简明的描述相应的框架和提醒分析，不输出冗余内容，结合笔记和跳转链接进行具体的复习，该文只作为大纲使用。</p>
<ul>
<li>适用的情况分析</li>
<li>算法的具体框架和思路</li>
<li>特殊情况描述</li>
<li>怎么读取命令行的输入，在笔试的时候可能会需要</li>
</ul>
<h2 id="c笔试读取输入的操作">C++笔试读取输入的操作</h2>
<p>待整理：</p>
<p><a href="https://blog.csdn.net/e01528/article/details/99206024" target="_blank" rel="noopener">Link1</a>
；<a href="https://blog.csdn.net/weixin_41506062/article/details/106888825?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1.control&amp;dist_request_id=&amp;depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1.control" target="_blank" rel="noopener">Link2</a>
</p>
<p>输入通常使用while+cin&raquo;来进行，这种方式也可以直接读入整行的string；</p>
<p>需要注意的是，这种方式的话，如果使用的是getline，当遇到换行符的时候cin会直接停止继续输入；</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">while</span><span class="p">(</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">a</span><span class="o">&gt;&gt;</span><span class="n">b</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 主要是按照类型来进行cin，操作应该是通过空格来分割的。
</span></span></span><span class="line"><span class="cl"><span class="c1">// 按照我们执行的次数来进行指定次数的读取操作
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="err">以指定符号分割的字符串输入</span>
</span></span><span class="line"><span class="cl"><span class="kt">char</span> <span class="n">str</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="mi">11</span><span class="p">];</span> 
</span></span><span class="line"><span class="cl"><span class="n">cin</span><span class="p">.</span><span class="n">getline</span><span class="p">(</span><span class="n">str</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="mi">11</span><span class="p">,</span> <span class="sc">&#39;,&#39;</span><span class="p">);</span>  <span class="c1">//接收最多10个字符 ,以‘，’作为结束符
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">cin</span><span class="p">.</span><span class="n">getline</span><span class="p">(</span><span class="n">str</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mi">11</span><span class="p">,</span> <span class="sc">&#39;,&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">cin</span><span class="p">.</span><span class="n">getline</span><span class="p">(</span><span class="n">str</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="mi">11</span><span class="p">);</span>     <span class="c1">//默认结束符 enter
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h2 id="常见数据类型和特殊专题">常见数据类型和特殊专题</h2>
<p>经常在那种预设值出问题，导致不会更新后续的max or min</p>
<h3 id="随机数问题">随机数问题</h3>
<p>470：用rand7 实现rand10：</p>
<p><strong>拒绝采样</strong> 实际上就是使用7进制来实现10，拒绝多余的选项，继续进行采样</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Solution</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">rand10</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kt">int</span> <span class="n">col</span><span class="p">,</span> <span class="n">row</span><span class="p">,</span> <span class="n">idx</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">do</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">row</span> <span class="o">=</span> <span class="n">rand7</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">            <span class="n">col</span> <span class="o">=</span> <span class="n">rand7</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">            <span class="n">idx</span> <span class="o">=</span> <span class="p">(</span><span class="n">row</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mi">7</span> <span class="o">+</span> <span class="n">col</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="n">idx</span> <span class="o">&gt;</span> <span class="mi">40</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="mi">1</span> <span class="o">+</span> <span class="n">idx</span> <span class="o">%</span> <span class="mi">10</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="环形问题">环形问题：</h3>
<ul>
<li>
<p>涉及到环形的问题的时候，如果我们是需要进行遍历操作的话，可以考虑通过取余的方式去解决；</p>
</li>
<li>
<p>如果是进行是否是环的判断，我们可以考虑双指针的问题（快慢指针），然后让一个先行之类的策略。</p>
</li>
</ul>
<h3 id="单调栈模板">单调栈模板</h3>
<p>下一个更大的xxx的问题；同样，单调的队列也是一个意思(可能就是有窗口的长度约束之类的)</p>
<p>还有像什么字典序的排列，这一题值得一做，是一个比较灵活的情况</p>
<ol>
<li>
<p>是一种保持栈中的数据从大到小的结构，当下一个比当前的数据更大的值出现的时候，我们就需要<strong>对数据进行记录</strong>，然后进行重排。</p>
</li>
<li>
<p>设计到环形的数据，也就是更大的下一个最终可能在前面的情况，我们考虑通过原长度的双倍长度去遍历，然后通过取余去取值即可</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span></span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code>index % n = new index;</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script></li>
<li>
<p>需要注意的是index和取值之间的关系也就是我们到底应该存index还是存值；</p>
</li>
<li>
<p>窗口是K，那么index到k-1就需要开始判断了，也就是第k个，可能这个时候就需要进行弹出之类的（这种情况是否应该使用双端队列）</p>
</li>
</ol>
<p>特殊取值问题，我们要考虑输入如果只有一个数字的情况下，还有两个size不等的情况下到底怎么做</p>
<h3 id="链表问题">链表问题</h3>
<p>这里有两类题需要我自己再揣摩一下，一个是K个一组反转（使用迭代+递归的方式），还有一个是求回文链表的两种技巧（快慢指针同时能判断奇偶的特性）</p>
<ul>
<li>其中典型的技巧就是双指针技巧和前序后续遍历技巧，以及快慢技巧</li>
<li>类通用的额外head来实现正向和后序遍历同时进行的过程。(比如判断回文链表)</li>
</ul>
<h3 id="二叉树问题">二叉树问题</h3>
<p>二叉树问题很多情况下表现为一个<strong>遍历和递归的</strong>问题，同时其中最重要的是3种遍历方式的特性：<strong>前序、中序、后序</strong>，典型的就是<code>重建二叉树</code>；下面这一题是比较有启发性的：</p>
<h4 id="二叉树中的最大路径和142">二叉树中的最大路径和（142）</h4>
<ul>
<li>return的值和中间进行判断，以及最终结果的统计值是不同的</li>
<li>所以维护一个全局的ans，来区分这个过程。</li>
</ul>
<h4 id="经典难题-序列化和反序列化">经典难题 序列化和反序列化</h4>
<p>这种用字符串来表示树的，一定要记得间隔和结尾是两个不同的符号来表征；</p>
<h3 id="动态规划问题">动态规划问题</h3>
<p>WORKFLOW：<strong>明确状态（DP表各个index对应的子状态含义）、明确状态转移的过程、通过状态转移判断迭代的方向、根据方向和题解确定base cases、根据状态的转移过程优化压缩dp表的空间</strong></p>
<p>题型方面实际上应该主要是下面的几类问题：</p>
<ul>
<li>能分成子问题的最优解问题</li>
<li>序列匹配问题</li>
<li>“逐步”的过程：博弈</li>
</ul>
<p>难点：实际上就是动态转移方程的构建和dp表的建立，我们要明确这样一个状态转移的过程。</p>
<p>思路：和递归是一样的，假设子问题解决了，到新问题，</p>
<p>压缩：要注意我们在删除维度的时候是不是会导致新的数据覆盖掉了需要的数据（决定好迭代的方向）</p>
<hr>
<h4 id="闫式dp分析法">闫式DP分析法：</h4>
<p>状态表示（把集合表现为数） &amp; 状态计算 （化整为零，划分成若干个子集去做，）</p>
<p>属性：max，min，count；（题目问的是什么）</p>
<p>划分子集依据：寻找最后一个不同点</p>
<p><a href="https://blog.csdn.net/weixin_44289697/article/details/105125613" target="_blank" rel="noopener">LINK1</a>
 ； <a href="https://www.acwing.com/file_system/file/content/whole/index/content/406072/" target="_blank" rel="noopener">Link2</a>
</p>
<p><strong>选择问题：</strong> <strong>每一个维度是一个条件</strong></p>
<p>第一个维度：我只考虑前i个问题（物品），第二个维度一般都是限制，存放属性（也就是最大的xxx）</p>
<p>最后一个不同点：对最后一个物品i，做出的不同选择，来进行状态转移</p>
<h4 id="正则表达式问题">正则表达式问题：</h4>
<p>永远的痛，我们怎么把他归化到小问题，也就是为什么我们最多只需要往回退一次</p>
<ul>
<li>考虑当前组合：匹配并丢弃（往前规划的时候j-2） j-1</li>
<li>匹配不丢弃（往前归化的时候j不变） i-1</li>
<li>不匹配。j-2</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Solution</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="kt">bool</span> <span class="n">isMatch</span><span class="p">(</span><span class="n">string</span> <span class="n">s</span><span class="p">,</span> <span class="n">string</span> <span class="n">p</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 考虑两种情况：普通的匹配和*号匹配
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="c1">// 建立DP-table 考虑初始情况
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="kt">int</span> <span class="n">m</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span> <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">bool</span><span class="o">&gt;&gt;</span> <span class="n">DP</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">bool</span><span class="o">&gt;</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="nb">false</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">        <span class="n">DP</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 下面这个可以转换成&amp;&amp;语句可能会更好看点
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">+=</span><span class="mi">2</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span><span class="p">(</span><span class="n">p</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="sc">&#39;*&#39;</span><span class="p">)</span> <span class="n">DP</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">DP</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="n">i</span><span class="o">-</span><span class="mi">2</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 下面开始状态转移
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">m</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span> <span class="p">(</span><span class="n">p</span><span class="p">[</span><span class="n">j</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="sc">&#39;*&#39;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="c1">// 其实就是考虑两种情况: 最后的不同，第一个方式是我们抛弃前一个元素，第二个方式就是正常匹配，用了且过，第三个方式是我们用了且保留，那么就会出现一种情况，也就是在i的上一个时刻，已经和我们当前的*匹配了，但是我们还在继续匹配，这里要注意，这里不是和dp[i-1][j-1]比，和这个比的话，实际上就是正常的对比了，看下面的else，i-1 *中包含了i-2 * ，所以前面的我们就不需要再重复考虑了
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>                    <span class="n">DP</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">DP</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">||</span> <span class="n">DP</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span> <span class="o">-</span> <span class="mi">2</span><span class="p">]</span>  <span class="o">||</span> <span class="n">DP</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">p</span><span class="p">[</span><span class="n">j</span> <span class="o">-</span> <span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="n">s</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">||</span> <span class="n">p</span><span class="p">[</span><span class="n">j</span> <span class="o">-</span> <span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="sc">&#39;.&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">                    
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">                <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="c1">// 如果没有*号的特殊情况下的时候，考虑就是前面的相等以及当前的相等，或者说就是.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>                    <span class="n">DP</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">DP</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">][</span><span class="n">j</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">p</span><span class="p">[</span><span class="n">j</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">s</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">||</span> <span class="n">p</span><span class="p">[</span><span class="n">j</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="sc">&#39;.&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">DP</span><span class="p">[</span><span class="n">m</span> <span class="o">-</span> <span class="mi">1</span><span class="p">][</span><span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="编辑距离">编辑距离</h4>
<p>这一题的二维很好写，也是一个帮助理解DP方法的一个很好的例子，但是在压缩成一维的时候有很多的细节这里要注意</p>
<ol>
<li>首先是初始化的问题，还有在内层循环要将第一个数的初始化在这里进行赋值，（第一行，和第n行的第一个需要被初始化）</li>
<li>这里i-1，j-1的形式就比较老生常谈了；</li>
<li>这里的if else 就变成必要的了！（所以能表达的更清楚的时候，大多数时候我们还是不要省略else，这样的话也能减少不必要的运算）（暂时还没搞清楚），同时这里的和自己进行min的方式就不能用了，因为我们原本是初始化成一个很大的数，但是在这里的象征意义就已经被改变了。</li>
</ol>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Solution</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">minDistance</span><span class="p">(</span><span class="n">string</span> <span class="n">word1</span><span class="p">,</span> <span class="n">string</span> <span class="n">word2</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 实际上这题已经很熟悉了，这里需要做的就是构建一个DP table，以及状态转移
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="c1">// 切分的状态就是string的index
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">if</span><span class="p">(</span><span class="n">word1</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> <span class="k">return</span> <span class="n">word2</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span><span class="p">(</span><span class="n">word2</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> <span class="k">return</span> <span class="n">word1</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 建立dp table
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">size_t</span> <span class="n">len1</span> <span class="o">=</span> <span class="n">word1</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="n">size_t</span> <span class="n">len2</span> <span class="o">=</span> <span class="n">word2</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">dp</span><span class="p">(</span><span class="n">len2</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 初始化base-case，当一个是空，另一个不是空的情况
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        
</span></span><span class="line"><span class="cl">        <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">len2</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 通过转移方程确定搜索的方向，从而确定遍历的方向，建立状态转移方程
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="kt">int</span> <span class="n">prec</span><span class="p">,</span> <span class="n">temp</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;=</span><span class="n">len1</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">            <span class="n">prec</span> <span class="o">=</span> <span class="n">dp</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span> <span class="n">dp</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">j</span><span class="o">&lt;=</span><span class="n">len2</span><span class="p">;</span><span class="n">j</span><span class="o">++</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">                <span class="c1">// dp i,j 象征着word1到i 变换到word2 需要的变换操作数，
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>                <span class="c1">// 当当前的值相等的时候
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>                <span class="n">temp</span> <span class="o">=</span> <span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span><span class="p">(</span><span class="n">word1</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">word2</span><span class="p">[</span><span class="n">j</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span> <span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">prec</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="k">else</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="c1">// 插入一个才能变道j
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>                    <span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">min</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span><span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">]),</span><span class="n">prec</span><span class="p">)</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">                <span class="n">prec</span> <span class="o">=</span> <span class="n">temp</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">dp</span><span class="p">[</span><span class="n">len2</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="俄罗斯套娃">俄罗斯套娃：</h4>
<p>这种两个维度，然后相互嵌套的问题，为了让其中的一个等大被抵消掉，所以一个逆序，另一个正序，然后寻找最长递增子序列。（找最长子序列的时候要找对搜索方向）</p>
<h4 id="子序列问题">子序列问题：</h4>
<p>一维的DP数组：这种子序列问题（子序列不同于子串），需要的一般都是以i为结尾的情况下，取得的最值，这样才符合我们需要归纳 的条件。</p>
<blockquote>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="c1">// 基础的算法模板如下
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="n">array</span><span class="p">.</span><span class="n">length</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span><span class="p">[]</span> <span class="n">dp</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="p">[</span><span class="n">n</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">i</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">     <span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="err">最值</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">+</span> <span class="p">...)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>在子数组<code>array[0..i]</code>中，以**<code>array[i]</code>**结尾的目标子序列（最长递增子序列）的长度是<code>dp[i]</code></strong>。</p>
</blockquote>
<p>二维的DP数组:这种思路其实用的更多，尤其是涉及到数组，两个字符串这样的问题的情况下，这种思路实际上涵盖了，包含一个字符串和两个字符串的情况</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="n">arr</span><span class="p">.</span><span class="n">length</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span><span class="p">[][]</span> <span class="n">dp</span> <span class="o">=</span> <span class="k">new</span> <span class="n">dp</span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="n">n</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">arr</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">arr</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> 
</span></span><span class="line"><span class="cl">            <span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">+</span> <span class="p">...</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span>
</span></span><span class="line"><span class="cl">            <span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="err">最值</span><span class="p">(...)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><ul>
<li>
<p><strong>涉及两个字符串/数组时</strong>（比如最长公共子序列），dp 数组的含义如下：</p>
<blockquote>
<p><strong>在子数组<code>arr1[0..i]</code>和子数组<code>arr2[0..j]</code>中，我们要求的子序列（最长公共子序列）长度为<code>dp[i][j]</code></strong>。</p>
<p>可以参考的是编辑距离和最长公共子序列两个文章</p>
</blockquote>
</li>
<li>
<p><strong>只涉及一个字符串/数组时</strong>（比如本文要讲的最长回文子序列），dp 数组的含义如下：</p>
<blockquote>
<p><strong>在子数组<code>array[i..j]</code>中，我们要求的子序列（最长回文子序列）的长度为<code>dp[i][j]</code></strong>。</p>
</blockquote>
</li>
</ul>
<p><strong>最长回文子序列</strong></p>
<p>假设i+1，j-1已经是最好的情况，当现在的两端不是相同，就没办法同时产生增益，也就是要么是左侧的最大值要么是右侧的最大值两种情况</p>
<p><strong>最长公共子序列</strong></p>
<p>实际上考虑下来和最长回文子序列是一样的问题，两边相同，同时产生增益，但是如果两边不同的话，就是两侧的其中一个max了。</p>
<p><strong>四键键盘问题</strong></p>
<p>实际上实现上和最长递增子序列稍微有点像，但是思路上的差别还是比较多的：要么就是一直按ａ，要么就是在某个地方开始ｃｖ所以我们存放的还是当前的最长值，然后通过一个内层循环，判断从哪开始cv就行。</p>
<h4 id="股票问题">股票问题</h4>
<p>简单的直接贪婪的计算正向差就完事了，或者通过迭代来计算前向的最大和；</p>
<p>动态规划方法的计算框架：定义两个维度，当天我们是否持有股票，然后进行状态的转移方程；（空间复杂度未优化的计算情况如下）（可以优化成4个值，实际上3个就好）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Solution</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">maxProfit</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">prices</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="n">prices</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 根据受伤是否持有股票来进行运算，存放第i天能获取的最大利益；
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">dp</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 可以先将购买消耗掉
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">dp</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="o">-</span><span class="n">prices</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// 容易出错的就是买卖的最终价格计算
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">prices</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">dp</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">][</span><span class="mi">0</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">            <span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">][</span><span class="mi">1</span><span class="p">],</span> <span class="n">dp</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">-</span> <span class="n">prices</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">dp</span><span class="p">[</span><span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">][</span><span class="mi">0</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>限制交易次数（最通用的情况）： 使用动态规划的话，+次数约束：把pair分开，变成两个加了k约束的dptable；188题，可以再看看</p>
<p>资金冻结一天，就将交易时间稍微修改一下，卖出后的那个值变成i-2就行了</p>
<p>每次需要手续费，我们只需要在购买的时候扣除手续费就行。</p>
<p><strong>状态机解法</strong></p>
<p>实际上也就第三题只进行两次交易的情况好一些，也就是说，当我们只进行一次买入的时候是s1，然后我们进行一次买入一次卖出的时候是s2，以此类推，然后再上一个s的情况下进行状态的更新就性了没什么特殊的地方。</p>
<p><strong>打家劫舍问题</strong>：</p>
<p>实际上像二叉树那样的题目可以和股票一样分成两个状态去做，也能够和之前是一摸一样的，用递归的方法加上备忘录去做，但是递归的方法实际上就是dfs，我们先递归到最底层然后加入备忘录然后进行计算，这样我们在递归的时候就要确定现在的这个值我们之前是不是已经计算过了。</p>
<h4 id="最坏情况下的最好">最坏情况下的最好</h4>
<p><strong>高楼扔鸡蛋问题</strong> : 通过碎或不碎来对问题切割成子问题，然后两个单调序列使用二分法查找；</p>
<h4 id="戳气球问题"><strong>戳气球问题</strong></h4>
<p>这题比较难就另外提出来说了：实际上思路就是假设i，j是戳破i，j这个开区间以后能够得到的最大的res，然后我们遍历每个k，其中的最大值就是i，j的最大值了。然后这就是个动态归化的问题，搜索方向其实也比较简单，写起来就没啥</p>
<h4 id="kms字符串匹配算法">KMS字符串匹配算法：</h4>
<p>基本想要实现的就是让指针i不走回头路，不会进行重复的扫描，理论上这样需要一个影子指针去做。</p>
<p>实际上就是设计一个delay，然后同步进行状态的推进，然后base case就是当匹配到i个字符的时候进行加1，然后main遇到每个元素后要跳转到哪，全问delay，只有匹配的时候进行下一个状态的演变</p>
<h3 id="博弈问题">博弈问题</h3>
<p>实际上是一种特殊的动态规划问题，这里的技巧是使用pair，然后将dp中的值定义为first：先手能取到的最高总分； sec：后手能取到的最值总分；</p>
<p>然后我们就能通过先后手和当前的状态图来计算得到一个状态传递方程了</p>
<h3 id="背包问题">背包问题</h3>
<p>实际上是动态规划的子问题，但是这里我们还是独立出来说一下</p>
<p>（核心）状态的选择：分别是重量、对应的item，存储当前的value，然后每次对item<strong>做0，1选择</strong>来做状态转移。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">knapsack</span><span class="p">(</span><span class="kt">int</span> <span class="n">W</span><span class="p">,</span> <span class="kt">int</span> <span class="n">N</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">wt</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">val</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// vector 全填入 0，base case 已初始化
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">dp</span><span class="p">(</span><span class="n">N</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">(</span><span class="n">W</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">w</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">w</span> <span class="o">&lt;=</span> <span class="n">W</span><span class="p">;</span> <span class="n">w</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">w</span> <span class="o">-</span> <span class="n">wt</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="c1">// 当前背包容量装不下，只能选择不装入背包
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>                <span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">w</span><span class="p">]</span> <span class="o">=</span> <span class="n">dp</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">][</span><span class="n">w</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="c1">// 装入或者不装入背包，择优
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>                <span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">w</span><span class="p">]</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">][</span><span class="n">w</span> <span class="o">-</span> <span class="n">wt</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">]]</span> <span class="o">+</span> <span class="n">val</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> 
</span></span><span class="line"><span class="cl">                               <span class="n">dp</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">][</span><span class="n">w</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">dp</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">W</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>分割等和子集</strong>： 需要注意，当我们进行bool转化和压缩的时候，为了防止被更新覆盖掉，所以我们最好还是使用反向的迭代方式</p>
<p><strong>零钱兑换问题</strong>：状态转移实际上还是和分割子集是一样的，就是如何将用不用这个item（因为可以是无数个），给归化出来。</p>
<blockquote>
<p>用其他硬币到j 用所有硬币到[j-coint[i]]</p>
</blockquote>
<h3 id="贪心算法">贪心算法</h3>
<p>实际上就是一种极端的思想，取各个最优的情况进行选择的这种思想：</p>
<ul>
<li>最长上升子序列：让子序列的末尾尽可能的小：
当我们大于数组的结尾的时候就给数组的结尾加长，不然就找到第一个比他小的数组后面那个数字给替换掉。在这里使用二分查找的思路。</li>
<li>区间重叠、破气球问题：按照区间结束得早来排序，最终归纳出重叠区间即可</li>
<li>跳跃游戏：没啥好说的就，贪，然后找到最远的地方，然后这个时候要注意一下，我们改如何去更新步数，就好（每一次的最远的边界更新一次距离即可）</li>
</ul>
<h3 id="回溯算法backtrack">回溯算法（backtrack）</h3>
<p><strong>解决一个回溯问题，实际上就是一个决策树的遍历过程</strong>。只需要考虑三个问题</p>
<p><strong>1、路径</strong>：也就是已经做出的选择。</p>
<p><strong>2、选择列表</strong>：也就是你当前可以做的选择。</p>
<p><strong>3、结束条件</strong>：也就是到达决策树底层，无法再做选择的条件。</p>
<p>具体代码框架：<strong>其核心就是 for 循环里面的递归，在递归调用之前「做选择」，在递归调用之后「撤销选择」</strong> 我觉得这里应该就是存储一个中间结果来做把。通过具体的代码来看看</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">result</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl"><span class="n">def</span> <span class="n">backtrack</span><span class="p">(</span><span class="err">路径</span><span class="p">,</span> <span class="err">选择列表</span><span class="p">)</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="err">满足结束条件</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">result</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="err">路径</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="err">选择</span> <span class="n">in</span> <span class="err">选择列表</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">        <span class="err">做选择</span>
</span></span><span class="line"><span class="cl">        <span class="n">backtrack</span><span class="p">(</span><span class="err">路径</span><span class="p">,</span> <span class="err">选择列表</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="err">撤销选择</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>全排列问题、组合问题、n皇后问题、子集问题、数独（主要是棋盘格子中的坐标转换，其他的和n皇后没什么区别）、合成括号生成（也就是分别对左右进行回溯，然后其他的也没什么区别了）</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Solution</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">permute</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">nums</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">res</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">backtrack</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="n">nums</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">nums</span><span class="p">.</span><span class="n">size</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">res</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="nf">backtrack</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;&amp;</span> <span class="n">res</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">output</span><span class="p">,</span> <span class="kt">int</span> <span class="n">first</span><span class="p">,</span> <span class="kt">int</span> <span class="n">len</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">first</span> <span class="o">==</span> <span class="n">len</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">res</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">output</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">first</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">len</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">swap</span><span class="p">(</span><span class="n">output</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">output</span><span class="p">[</span><span class="n">first</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">            <span class="n">backtrack</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="n">output</span><span class="p">,</span> <span class="n">first</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">len</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="n">swap</span><span class="p">(</span><span class="n">output</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">output</span><span class="p">[</span><span class="n">first</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="bfs算法">BFS算法：</h3>
<p>其他的也不多说了，实际上就一个重点，那就是要使用队列这个数据结构来做，BFS也有一个特点就是，找到的路径一般是最短的， 也就是和七点的最短距离，但是相应的我们会需要更多的空间复杂度。</p>
<p>在BFS需要深度的时候，我们可以</p>
<ul>
<li>同时用pair来维护一个深度信息.</li>
<li>每次把queue中的数据清空再来size++</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// 计算从起点 start 到终点 target 的最近距离
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kt">int</span> <span class="nf">BFS</span><span class="p">(</span><span class="n">Node</span> <span class="n">start</span><span class="p">,</span> <span class="n">Node</span> <span class="n">target</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">Queue</span><span class="o">&lt;</span><span class="n">Node</span><span class="o">&gt;</span> <span class="n">q</span><span class="p">;</span> <span class="c1">// 核心数据结构
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">Set</span><span class="o">&lt;</span><span class="n">Node</span><span class="o">&gt;</span> <span class="n">visited</span><span class="p">;</span> <span class="c1">// 避免走回头路
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">    <span class="n">q</span><span class="p">.</span><span class="n">offer</span><span class="p">(</span><span class="n">start</span><span class="p">);</span> <span class="c1">// 将起点加入队列
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">visited</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">start</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">step</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">// 记录扩散的步数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="n">q</span> <span class="n">not</span> <span class="n">empty</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kt">int</span> <span class="n">sz</span> <span class="o">=</span> <span class="n">q</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="cm">/* 将当前队列中的所有节点向四周扩散 */</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">sz</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">Node</span> <span class="n">cur</span> <span class="o">=</span> <span class="n">q</span><span class="p">.</span><span class="n">poll</span><span class="p">();</span> <span class="c1">// 访问队列中的当前节点
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="cm">/* 划重点：这里判断是否到达终点 */</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">cur</span> <span class="n">is</span> <span class="n">target</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span> <span class="n">step</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="cm">/* 将 cur 的相邻节点加入队列 */</span>
</span></span><span class="line"><span class="cl">            <span class="k">for</span> <span class="p">(</span><span class="n">Node</span> <span class="nl">x</span> <span class="p">:</span> <span class="n">cur</span><span class="p">.</span><span class="n">adj</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span> <span class="p">(</span><span class="n">x</span> <span class="n">not</span> <span class="n">in</span> <span class="n">visited</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="n">q</span><span class="p">.</span><span class="n">offer</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">                    <span class="n">visited</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="cm">/* 划重点：更新步数在这里 */</span>
</span></span><span class="line"><span class="cl">        <span class="n">step</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>转盘锁问题</strong> 实际上我们可以看成每个状态有8个可能的前进方向，然后用BFS就能优先遍历到。如果是回溯的话也差不多的写，但是问题是这样的搜索时间是一定需要遍历完所有的可能性的。实际上回溯就是我们每一步的变换+4就行了，基本的答题代码还是一致的。</p>
<p>用HASH来避免重复的遍历</p>
<p>双向的bfs优化：维护两个set（用来交替进行）和一个visited。</p>
<p><strong>滑动谜题</strong>：实际上也能分析成是一个树一样的决策结构，然后我们希望找到最低的深度，这样的话，关键还是遍历还有一个避免重复。</p>
<p>Trick：转化为维度1来节省空间和时间，也可以直接将邻居列出来</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl">    <span class="c1">// 记录一维字符串的相邻索引
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">neighbor</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">2</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">5</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">4</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">5</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">2</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="分治算法">分治算法</h3>
<p>实际上和回溯，动态规划都是特殊的递归：</p>
<blockquote>
<p>回溯算法就一种简单粗暴的算法技巧，说白了就是一个暴力穷举算法，比如让你 用回溯算法求<a href="http://mp.weixin.qq.com/s?__biz=MzAxODQxMDM0Mw==&amp;mid=2247485007&amp;idx=1&amp;sn=ceb42ba2f341af34953d158358c61f7c&amp;chksm=9bd7f847aca071517fe0889d2679ead78b40caf6978ebc1d3d8355d6693acc7ec3aca60823f0&amp;scene=21#wechat_redirect" target="_blank" rel="noopener">子集、全排列、组合</a>
，你就穷举呗，就考你会不会漏掉或者多算某些情况。</p>
<p>动态规划是一类算法问题，肯定是让你求最值的。因为动态规划问题拥有 <a href="http://mp.weixin.qq.com/s?__biz=MzAxODQxMDM0Mw==&amp;mid=2247484832&amp;idx=1&amp;sn=44ad2505ac5c276bf36eea1c503b78c3&amp;chksm=9bd7fba8aca072be32f66e6c39d76ef4e91bdbf4ef993014d4fee82896687ad61da4f4fc4eda&amp;scene=21#wechat_redirect" target="_blank" rel="noopener">最优子结构</a>
，可以通过状态转移方程从小规模的子问题最优解推导出大规模问题的最优解。</p>
<p>分治算法呢，可以认为是一种算法思想，通过将原问题分解成小规模的子问题，然后根据子问题的结果构造出原问题的答案。这里有点类似动态规划，所以说运用分治算法也需要满足一些条件，你的原问题结果应该可以通过合并子问题结果来计算。</p>
</blockquote>
<p>基本框架：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">sort</span><span class="p">(</span><span class="kt">int</span><span class="p">[]</span> <span class="n">nums</span><span class="p">,</span> <span class="kt">int</span> <span class="n">lo</span><span class="p">,</span> <span class="kt">int</span> <span class="n">hi</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">mid</span> <span class="o">=</span> <span class="p">(</span><span class="n">lo</span> <span class="o">+</span> <span class="n">hi</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/****** 分 ******/</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 对数组的两部分分别排序
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">sort</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span> <span class="n">lo</span><span class="p">,</span> <span class="n">mid</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">sort</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span> <span class="n">mid</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">hi</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/****** 治 ******/</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 合并两个排好序的子数组
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">merge</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span> <span class="n">lo</span><span class="p">,</span> <span class="n">mid</span><span class="p">,</span> <span class="n">hi</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h3 id="双指针二分查找滑动窗口">双指针&amp;&amp;二分查找&amp;&amp;滑动窗口</h3>
<p><strong>一些常见的用法：</strong>（实际上要么就是两个方向，要么就是两个步调）</p>
<ol>
<li>是否有环：相遇可以判定有环；</li>
<li>找到环的起始点：相遇后，把一个调到头，同速前进，再次相遇即是起始点。</li>
<li>链表的中点：快慢指针，快指针到达终点。
延申问题：对链表进行归并排序，通过快慢指针实现二分的操作，合并两个有序链表。</li>
<li>起始点偏差：先让一个指针走k步，另一个指针再出发，寻找链表的倒数第k个元素</li>
</ol>
<p><strong>类型题总结</strong></p>
<ol>
<li><strong>快慢指针</strong>：链表操作，归并排序找中点，链表成环搞判定；</li>
<li><strong>左右指针</strong>：反转数组，二分搜索</li>
<li><strong>滑动窗口</strong>：字串问题，左右指针滑动，前后并进</li>
</ol>
<p><strong>快慢指针的常见用法：</strong></p>
<ol>
<li>二分查找算法，没啥好说的</li>
<li>子数组之和：只要<strong>数组有序</strong>，就要想到双指针技巧。通过调节left和right来调整sum的大小。找到对应的区间</li>
<li>反转数组：从前或从后出发，然后直接互换。</li>
<li>下面讲的滑动窗口</li>
</ol>
<p>27.移除元素那一题，我原本写法的优越性，这里可以掌握一下，为啥用while的方式的话，效果反而不好呢</p>
<p>移除0 这个题还是有一些细节的，普通的写很容易出错</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Solution</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="n">moveZeroes</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">nums</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">nums</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 直接进行值的改变是不是好一点，然后在后面进行添加就好了
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="kt">int</span> <span class="n">index1</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="kt">int</span> <span class="n">index2</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">while</span><span class="p">(</span><span class="n">index2</span> <span class="o">&lt;</span> <span class="n">nums</span><span class="p">.</span><span class="n">size</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">nums</span><span class="p">[</span><span class="n">index2</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">nums</span><span class="p">[</span><span class="n">index1</span><span class="p">]</span> <span class="o">=</span> <span class="n">nums</span><span class="p">[</span><span class="n">index2</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span> <span class="p">(</span><span class="n">index1</span> <span class="o">!=</span> <span class="n">index2</span><span class="p">)</span> <span class="n">nums</span><span class="p">[</span><span class="n">index2</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="n">index1</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="n">index2</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="二分查找了解了问题不大晚上再来看下就好">二分查找：(了解了，问题不大，晚上再来看下就好)</h4>
<p>三种情况：找到值，左侧边界，右侧边界（）</p>
<p>找到值的方式就没什么好说的：我们直接当相等的时候返回就行，我们主要分析一下左侧边界和右侧边界的情况到底是什么含义：</p>
<ul>
<li>左侧边界：满足某个条件的最左边（最小值），比如大于等于二的边界（最左边的那个2）；</li>
<li>右侧边界：满足某个条件的最右边（最大值），比如小于等于二的边界（最右边的那个2）；</li>
</ul>
<p>结论1：<strong>两侧的边界是对称的</strong>：实际上画一下还是很容易分析出来的（<strong>&gt;=</strong> / **&lt;=**的direction）：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>c&#43;&#43;</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="err">左侧边界：</span> <span class="o">&gt;=</span>
</span></span><span class="line"><span class="cl"><span class="o">&lt;:</span> <span class="n">l</span><span class="o">=</span><span class="n">mid</span><span class="o">+</span><span class="mi">1</span> 
</span></span><span class="line"><span class="cl"><span class="o">&gt;=</span> <span class="o">:</span> <span class="n">r</span> <span class="o">=</span> <span class="n">mid</span><span class="o">-</span><span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="err">检测左侧边界是否合理</span>
</span></span><span class="line"><span class="cl"><span class="k">return</span> <span class="n">l</span><span class="err">；</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span></span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code>右侧边界： &lt;=
&lt;=: l=mid+1 
&gt; : r = mid-1
检测右侧边界是否合理
return r；</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>结论2：**&gt;= 换成&gt; :**或者小&lt;=换成&lt;:<strong>只需要换一下相等</strong>的情况即可：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="err">左侧边界：</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="o">&lt;=:</span> <span class="n">l</span><span class="o">=</span><span class="n">mid</span><span class="o">+</span><span class="mi">1</span> 
</span></span><span class="line"><span class="cl"><span class="o">&gt;</span> <span class="o">:</span> <span class="n">r</span> <span class="o">=</span> <span class="n">mid</span><span class="o">-</span><span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="err">检测左侧边界是否合理</span>
</span></span><span class="line"><span class="cl"><span class="k">return</span> <span class="n">l</span><span class="err">；</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="err">右侧边界：</span><span class="o">&lt;</span>
</span></span><span class="line"><span class="cl"><span class="o">&lt;:</span> <span class="n">l</span><span class="o">=</span><span class="n">mid</span><span class="o">+</span><span class="mi">1</span> 
</span></span><span class="line"><span class="cl"><span class="o">&gt;=</span> <span class="o">:</span> <span class="n">r</span> <span class="o">=</span> <span class="n">mid</span><span class="o">-</span><span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="err">检测右侧边界是否合理</span>
</span></span><span class="line"><span class="cl"><span class="k">return</span> <span class="n">r</span><span class="err">；</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>使用二分查找来解决数组的题目</strong></p>
<p>存在如下的遍历架构显然是使用<strong>二分查找</strong>的方法来优化的：koko吃香蕉，货物运输</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">isOK</span><span class="p">(</span><span class="n">i</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">answer</span><span class="p">;</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="nsum问题">nsum问题</h4>
<p>（2-sum）这种问题的关键在于，排序后指针双向而行的时候，怎么排除重复的元素（可以使用while直接跳过当前的指即可）</p>
<p>（3-4sum）首先取第一个值，然后对剩下的部分求n sum 穷举，（还是需要sort的）</p>
<h4 id="滑动窗口">滑动窗口：</h4>
<p><strong>基本的框架思想：</strong></p>
<ol>
<li>左闭右开称为窗口；</li>
<li>先增大right到满足，再缩减left直到不满足，每次增加left都要更新一次结果；</li>
<li>重复2，直到r-&gt;end;</li>
</ol>
<p>具体的实现框架：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cm">/* 滑动窗口算法框架 */</span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">slidingWindow</span><span class="p">(</span><span class="n">string</span> <span class="n">s</span><span class="p">,</span> <span class="n">string</span> <span class="n">t</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">unordered_map</span><span class="o">&lt;</span><span class="kt">char</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">need</span><span class="p">,</span> <span class="n">window</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">char</span> <span class="nl">c</span> <span class="p">:</span> <span class="n">t</span><span class="p">)</span> <span class="n">need</span><span class="p">[</span><span class="n">c</span><span class="p">]</span><span class="o">++</span><span class="p">;</span> <span class="c1">// 初始化状态，便于搜索
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">left</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">right</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">valid</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>  <span class="c1">// 统计满足情况的数有多少，和需要的匹配时更新答案
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">while</span> <span class="p">(</span><span class="n">right</span> <span class="o">&lt;</span> <span class="n">s</span><span class="p">.</span><span class="n">size</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// c 是将移入窗口的字符
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="kt">char</span> <span class="n">c</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="n">right</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 右移窗口
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">right</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 进行窗口内数据的一系列更新
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="p">...</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="cm">/*** debug 输出的位置 ***/</span>
</span></span><span class="line"><span class="cl">        <span class="n">printf</span><span class="p">(</span><span class="s">&#34;window: [%d, %d)</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">left</span><span class="p">,</span> <span class="n">right</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="cm">/********************/</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">// 判断左侧窗口是否要收缩
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">while</span> <span class="p">(</span><span class="n">window</span> <span class="n">needs</span> <span class="n">shrink</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// d 是将移出窗口的字符
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="kt">char</span> <span class="n">d</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="n">left</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// 左移窗口
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="n">left</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// 进行窗口内数据的一系列更新
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="p">...</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p><strong>典型例题（76）最小覆盖字串</strong>：实现代码后续再做一次</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Solution</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">string</span> <span class="n">minWindow</span><span class="p">(</span><span class="n">string</span> <span class="n">s</span><span class="p">,</span> <span class="n">string</span> <span class="n">t</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">s</span><span class="p">.</span><span class="n">empty</span><span class="p">()</span> <span class="o">||</span> <span class="n">t</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> <span class="k">return</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 考虑到出现重复字符的情况，所以需要有一个int进行计数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">unordered_map</span><span class="o">&lt;</span><span class="kt">char</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">need</span><span class="p">,</span> <span class="n">windows</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="kt">int</span> <span class="n">l</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">r</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">n</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 统计需要的每个字符的数量
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">for</span> <span class="p">(</span><span class="kt">char</span> <span class="nl">c</span> <span class="p">:</span> <span class="n">t</span><span class="p">)</span> <span class="n">need</span><span class="p">[</span><span class="n">c</span><span class="p">]</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="kt">int</span> <span class="n">valid</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">needv</span> <span class="o">=</span> <span class="n">need</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="kt">int</span> <span class="n">start</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">lens</span> <span class="o">=</span> <span class="n">INT_MAX</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="k">while</span> <span class="p">(</span><span class="n">r</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="kt">char</span> <span class="n">temp</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="n">r</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">            <span class="n">r</span><span class="o">++</span><span class="p">;</span> <span class="c1">// 每次就进行所有的缩减边界的行为
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="k">if</span> <span class="p">(</span><span class="n">need</span><span class="p">.</span><span class="n">count</span><span class="p">(</span><span class="n">temp</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">windows</span><span class="p">[</span><span class="n">temp</span><span class="p">]</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="c1">// 只在这里进行状态的变换，不进行判断
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>                <span class="k">if</span> <span class="p">(</span><span class="n">windows</span><span class="p">[</span><span class="n">temp</span><span class="p">]</span> <span class="o">==</span> <span class="n">need</span><span class="p">[</span><span class="n">temp</span><span class="p">])</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="n">valid</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// cout&lt;&lt;r&lt;&lt;&#34;now , l &#34;&lt;&lt;l&lt;&lt;endl;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="c1">// 左闭右开区间
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="k">while</span> <span class="p">(</span><span class="n">valid</span> <span class="o">==</span> <span class="n">needv</span> <span class="o">&amp;&amp;</span><span class="n">l</span> <span class="o">&lt;</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span> <span class="p">(</span><span class="n">r</span> <span class="o">-</span> <span class="n">l</span> <span class="o">&lt;</span> <span class="n">lens</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="n">start</span> <span class="o">=</span> <span class="n">l</span><span class="p">;</span> <span class="n">lens</span> <span class="o">=</span> <span class="n">r</span> <span class="o">-</span> <span class="n">l</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                    <span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">lens</span><span class="o">&lt;&lt;</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                <span class="kt">char</span> <span class="n">temp2</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="n">l</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span> <span class="p">(</span><span class="n">need</span><span class="p">.</span><span class="n">count</span><span class="p">(</span><span class="n">temp2</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="k">if</span> <span class="p">(</span><span class="n">windows</span><span class="p">[</span><span class="n">temp2</span><span class="p">]</span> <span class="o">==</span> <span class="n">need</span><span class="p">[</span><span class="n">temp2</span><span class="p">])</span> <span class="n">valid</span><span class="o">--</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                    <span class="n">windows</span><span class="p">[</span><span class="n">temp2</span><span class="p">]</span><span class="o">--</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">                <span class="n">l</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">lens</span><span class="o">==</span><span class="n">INT_MAX</span><span class="o">?</span><span class="s">&#34;&#34;</span><span class="o">:</span><span class="n">s</span><span class="p">.</span><span class="n">substr</span><span class="p">(</span><span class="n">start</span><span class="p">,</span><span class="n">lens</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>567题的实现细节要看懂：因为是排列，所以长度一定要相同，所以我们每一次递进right的时候同时收紧left就行</p>
<h4 id="盛水最多的容器">盛水最多的容器</h4>
<p>这一题的思路实际上还是典型的如何去缩减这样的问题规模上比较巧妙</p>
<p>也就是怎么去排除不可能的项，来确定我们的移动方向</p>
<h3 id="union-find-并查算法">Union-Find 并查算法</h3>
<p><strong>判断连通性的算法</strong>：具体实现上，我们实际上就是通过父节点是否相同去判断的；这实际上是一种反向的链表，也就是我们的指针是parent而不是指向next的；</p>
<p><strong>指针指向父节点，根节点指向子集</strong></p>
<p>如果要通过这种方式去判断联通的话，那么树的平衡性就是特别重要的问题，也就是我们每次进行接入的时候，我们最好都对该森林进行指向性优化：</p>
<ul>
<li>如果我们的parent有parent，我们就直接指向parent？is that right？</li>
<li>每次将小树接到大树后面，而不是反过来；</li>
</ul>
<p>需要实现的方法：</p>
<p>find（par == self，在find的时候进行压缩）、 connect（是否联通）、 Union（链接，需要优化）</p>
<blockquote>
<p>被围绕的区域130：实际上是一个DFS的题目，我们可以展开成一维去实现，同时在这种情况下使用UF也是可以的，需要注意到的是，每次的四个方向的边界判断。（这应该是这题的难点）</p>
</blockquote>
<h3 id="排序算法总结">排序算法总结：</h3>
<p>各类时间复杂度，思想，实现 （最后进行正合理和分析）</p>
<p><a href="https://www.cnblogs.com/zwtgyh/p/10631760.html" target="_blank" rel="noopener">参考链接1很直观</a>
；<a href="https://www.nowcoder.com/discuss/85719?type=0&amp;order=7&amp;pos=25&amp;page=1&amp;source_id=discuss_center_0_nctrack&amp;channel=1009" target="_blank" rel="noopener">参考链接2</a>
</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="Image/image-20200701160041081-1615019961668.png">
    <img alt="image-20200701160041081-1615019961668" loading="lazy" src="Image/image-20200701160041081-1615019961668.png"class="responsive-image" src="Image/image-20200701160041081-1615019961668.png" style="display: block; margin: 0 auto;"
      alt="image-20200701160041081-1615019961668"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h4 id="一插入排序">一、插入排序：</h4>
<p>实现：实际上就是对index前面的数据进行从后往前的遍历，遍历过程&gt;index的情况下直接后移，找到合适的位置的时候就将index-&gt;value 放到new index中</p>
<ul>
<li>思想：每步将一个待排序的记录，按其顺序码大小插入到前面已经排序的字序列的合适位置，直到全部插入排序完为止。</li>
<li>关键问题：在前面已经排好序的序列中找到合适的插入位置。</li>
<li>方法： 直接插入排序、二分插入排序、希尔排序</li>
</ul>
<h5 id="直接插入排序">直接插入排序</h5>
<ul>
<li>
<p>插入排序的最好情况是数组已经有序，此时只需要进行n-1次比较，时间复杂度为O(n)</p>
</li>
<li>
<p>最坏情况是数组逆序排序，此时需要进行n(n-1)/2次比较以及n-1次赋值操作（插入）</p>
</li>
<li>
<p>平均来说插入排序算法的复杂度为O(n2)</p>
</li>
<li>
<p>空间复杂度上，直接插入法是就地排序，空间复杂度为(O(1))</p>
<h5 id="二分插入排序-实际上就是修改了前面的搜索过程">二分插入排序 ：实际上就是修改了前面的搜索过程</h5>
</li>
<li>
<p>最坏情况：每次都在有序序列的起始位置插入，则整个有序序列的元素需要后移，时间复杂度为O(n2)</p>
</li>
<li>
<p>最好情况：待排序数组本身就是正序的，每个元素所在位置即为它的插入位置，此时时间复杂度仅为比较时的时间复杂度，为O(log2n)</p>
</li>
<li>
<p>平均情况：O(n2)，实际上就是将搜索的过程变成了logN</p>
</li>
<li>
<p>空间复杂度上，二分插入也是就地排序，空间复杂度为(O(1))。</p>
</li>
</ul>
<h5 id="希尔排序缩小增量排序">希尔排序：缩小增量排序</h5>
<p>实际上就是根据一个增量序列将原数组切分成一个个子序列然后进行插入排序，然后增量越来越小，最后增量为一进行i一次整体的排序（利用的是直接插入排序在小数组上时间效率高的特点）</p>
<ul>
<li>增量排序的时间复杂度依赖于所取增量序列的函数，但是到目前为止还没有一个最好的增量序列.有人在大量的实验后得出结论;当n在某个特定的范围后希尔排序的比较和移动次数减少至n^1.3 不管增量序列如何取值，都应该满足最后一个增量值为1。</li>
<li>有文献指出，当增量序列为d[k]=2^(t-k+1)^时，希尔排序的时间复杂度为O(n^1.5), 其中t为排序趟数。</li>
<li>空间复杂度上，SHELL插入也是就地排序，空间复杂度为(O(1))。</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// shell 排序
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="cp"># include&lt;vector&gt;
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">const</span> <span class="kt">int</span> <span class="n">INCRGAP</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">shellsort</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="n">nums</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">insertNum</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 首先计算出各个GAP，然后基于GAP进行插入排序
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">gap</span> <span class="o">=</span> <span class="n">nums</span><span class="p">.</span><span class="n">size</span><span class="p">()</span><span class="o">/</span><span class="n">INCRGAP</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// GAP&gt;=1
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">while</span><span class="p">(</span><span class="n">gap</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 实现插入排序；每一个树按照gap去找其前面的数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">for</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">gap</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="n">nums</span><span class="p">.</span><span class="n">size</span><span class="p">();</span><span class="n">i</span><span class="o">++</span> <span class="p">){</span>
</span></span><span class="line"><span class="cl">            <span class="kt">int</span> <span class="n">temp</span> <span class="o">=</span> <span class="n">nums</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">            <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="k">while</span><span class="p">(</span><span class="n">j</span><span class="o">&gt;=</span><span class="n">gap</span> <span class="o">&amp;&amp;</span> <span class="n">nums</span><span class="p">[</span><span class="n">j</span><span class="o">-</span><span class="n">gap</span><span class="p">]</span><span class="o">&gt;</span><span class="n">temp</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">                <span class="n">nums</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">nums</span><span class="p">[</span><span class="n">j</span><span class="o">-</span><span class="n">gap</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">                <span class="n">j</span><span class="o">-=</span><span class="n">gap</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// 当数字到了最前面或者第一个比他小的时候，插入
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="n">nums</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">temp</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="n">gap</span> <span class="o">/=</span> <span class="n">INCRGAP</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span>
</span></span><span class="line"><span class="cl">    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">a</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">41</span><span class="p">,</span><span class="mi">23</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">23</span><span class="p">,</span><span class="mi">53</span><span class="p">,</span><span class="mi">123</span><span class="p">,</span><span class="mi">1</span><span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="n">shellsort</span><span class="p">(</span><span class="n">a</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span><span class="p">(</span><span class="k">auto</span> <span class="nl">i</span><span class="p">:</span><span class="n">a</span><span class="p">)</span>	<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">i</span><span class="o">&lt;&lt;</span><span class="s">&#34;  &#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">endl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="二选择排序">二、选择排序：</h4>
<h5 id="直接选择排序">直接选择排序：</h5>
<ul>
<li>思想：每趟从待排序的记录序列中选择关键字最小的记录放置到已排序表的最后（tail）位置，直到全部排完。</li>
<li>关键问题：在剩余的待排序记录序列中找到最小关键码记录。</li>
</ul>
<p>实际上很明（显就是遍历求最值，O（n^2）</p>
<h5 id="堆排序">堆排序</h5>
<p>由于堆我们知道可以通过VECTOR，然后下标<code>*2 \ *2+1</code>来索引树结构，然后我们把大顶堆和末尾的数字交换位置，并重新建堆，重复这样的过程即可。</p>
<p>时间复杂度主要来自：1. 建堆 2. 调整堆</p>
<ul>
<li>堆排序的时间复杂度主要由两部分组成：初始化建堆和每次弹出堆顶元素后重新建堆的过程</li>
<li>初始化建堆过程的时间复杂度O(n)：假设堆的高度为k，则从倒数第二层右边的节点开始，这一层的节点都要进行子节点比较然后选择是否交换，倒数第三层类似，一直到第一层(即层数从k-1到1)；那么总的时间为 $(2^{(i-1)})*(k-i)$ ，其中i表示第i层(范围是k-1到1)，2^(i-1)表示该层上有多少元素，(k-i)表示子树上要比较的次数，即 $S = 2^{(k-2)}*1 + 2^{(k-3)}<em>2 + 2^{(k-4)}<em>3 + &hellip; + 2^1</em>(k-2) + 2^0</em>(k-1)$ ，使用错位相减法(用常数2来辅助转换，两边都乘以2再减去原等式)得到S = 2^(K-1) + 2^(K-2) + 2^(K-3) + &hellip; + 2 - (K-1)，忽略最后一项常数项就是等比数列，即 $S=2^k-2-(k-1)=2^k-k-1$ ，又因为k为完全二叉树的深度，所以有 2^k &lt;= n &lt; 2^k-1，可以认为k = logn，综上所述S = n - logn -1，所以时间复杂度为O(n)</li>
<li>弹出堆顶元素后重建堆过程的时间复杂度O(nlogn)：循环n-1次，每次都从跟节点往下循环查找所以每一次时间都是logn，总时间为(n-1)*logn = nlogn - logn</li>
<li>故堆排序的时间复杂度为O(n) + O(nlogn) = O(nlogn)</li>
<li>堆排序是接地排序，所以空间复杂度为常数O(1)</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">abjust_heap</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">nums</span><span class="p">,</span> <span class="kt">int</span> <span class="n">index</span><span class="p">,</span> <span class="kt">int</span> <span class="n">lens</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 根据二叉树的性质，索引到子节点的坐标
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">// TODO:但是还要判断越不越界(这里由于我们不是堆，而是一个排序的过程，长度在变，所以需要这个参数的输入)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="n">lens</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">left</span> <span class="o">=</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">index</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">n</span> <span class="o">?</span> <span class="mi">2</span> <span class="o">*</span> <span class="nl">index</span> <span class="p">:</span> <span class="n">index</span><span class="p">,</span> <span class="n">right</span> <span class="o">=</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">index</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">n</span> <span class="o">?</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">index</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">:</span> <span class="n">index</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 如果越界就赋予原值，也就是不改变。
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">max_child</span> <span class="o">=</span> <span class="n">nums</span><span class="p">[</span><span class="n">left</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">nums</span><span class="p">[</span><span class="n">right</span><span class="p">]</span> <span class="o">?</span> <span class="nl">left</span> <span class="p">:</span> <span class="n">right</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 和其中比较大的那个值互换，如果越界了是自己，和自己换
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">if</span> <span class="p">(</span><span class="n">nums</span><span class="p">[</span><span class="n">index</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">nums</span><span class="p">[</span><span class="n">max_child</span><span class="p">])</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">swap</span><span class="p">(</span><span class="n">nums</span><span class="p">[</span><span class="n">index</span><span class="p">],</span> <span class="n">nums</span><span class="p">[</span><span class="n">max_child</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// FIXME: 如果位置变了，要对变换的位置进行继续的递归
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">abjust_heap</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span> <span class="n">max_child</span><span class="p">,</span> <span class="n">n</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">heapsort</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">nums</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 通过下标索引来建立堆
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">// 由于二叉树的叶节点一定是总数的一半左右（len/2 or len/2+1）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">// 然后再根据数值和坐标的映射关系-1.可以知道非叶子节点的坐标是(len/2-1)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="n">nums</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 首先进行建堆的过程
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="p">(</span><span class="n">n</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">--</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 从倒数第二层开始一个个的进行交换
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">abjust_heap</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span><span class="n">n</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 然后依次弹出头部元素进行测试；
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">--</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">swap</span><span class="p">(</span><span class="n">nums</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">nums</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">        <span class="n">abjust_heap</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="三交换排序">三、交换排序：</h4>
<h5 id="冒泡排序">冒泡排序：</h5>
<p>就是对相邻的两个数进行比较，然后将大数往后放，把小数放到前面，第一次冒泡到n-i，递减排序完就行。</p>
<ul>
<li>最坏情况：冒泡排序要进行n-1轮排序循环，每轮排序循环中序列都是非正序的，则每轮排序循环中要进行n-i次比较(1&lt;=i&lt;=n-1)，即其外循环执行n-1次，内循环最多执行n次，最少执行1次，由于内循环执行次数是线性的，故内循环平均执行(n+1)/2次，时间复杂度计算为((n-1)(n+1))/2=(-1)/2 ，时间复杂度为O(n2)</li>
<li>最好情况：待排序数组本身就是正序的，一轮扫描即可完成排序，此时时间复杂度仅为比较时的时间复杂度，为O(n)</li>
<li>平均情况：O(n2)</li>
<li>空间复杂度就是在交换元素时那个临时变量所占的内存空间，最优的空间复杂度就是开始元素顺序已经排好了，则空间复杂度为0，最差的空间复杂度就是开始元素逆序排序了，则空间复杂度为O(n)，平均的空间复杂度为O(1)</li>
</ul>
<h5 id="快速排序">快速排序：</h5>
<p>**基本思想：**选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一轮扫描，将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分，直到各区间只有一个数。</p>
<ul>
<li>最好情况：是每轮划分都将待排序列正好分为两部分，那么每部分需要的时间为上一轮的1/2。如果排序n个元素的序列，其递归树深度为[logn]+1即仅需递归logn次，需要总时间为T(n)的话，第一次需要扫描整个序列，做n次比较，然后将序列一分为二，这两部分各自还需要T(n/2)的时间，依次划分下去：T(n) = 2<em>T(n/2)+n  T(n) = 2</em>(2*(T(n/4)+n/2)+n = 4<em>T(n/4)+2n 等等，且T(1) = 0，所以T(n) = n</em>T(1) + n*logn = O(nlogn)</li>
<li>最坏情况：当待排序列为有序序列(正序或倒序)，每次划分后得到的情况是一侧有1个元素，另一侧是其余元素，则最终要进行n-1轮循环，且第i次循环要进行n-i次比较，总比较次数为n-1 + n-2 + &hellip; + 1 = n(n-1)/2，即时间复杂度为O(n2)</li>
<li>空间复杂度待补充。</li>
</ul>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">quickSortPartition</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">s</span><span class="p">,</span> <span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">//Swap(s[l], s[(l + r) / 2]); //若以中间数为基准，则先将中间的这个数和第一个数交换即可
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">l</span><span class="p">,</span> <span class="n">j</span> <span class="o">=</span> <span class="n">r</span><span class="p">,</span> <span class="n">x</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="n">l</span><span class="p">];</span> <span class="c1">//将最左元素记录到x中
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">while</span> <span class="p">(</span><span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 从右向左找第一个&lt;x的数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="c1">// 无需考虑下标越界（有i的约束）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">while</span> <span class="p">(</span><span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span> <span class="o">&amp;&amp;</span> <span class="n">s</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="n">x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">j</span><span class="o">--</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span><span class="p">)</span> <span class="c1">// 满足这个条件实际上就是说，已经找到了。不满足就是没找到、
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="n">j</span><span class="p">];</span> <span class="c1">//直接替换掉最左元素，如果没找到的话，就不需要换。因为上面有约束
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 从左向右找第一个&gt;x的数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">while</span> <span class="p">(</span><span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span> <span class="o">&amp;&amp;</span> <span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="n">x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">i</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="c1">//替换掉最右元素(已在最左元素中有备份）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="c1">//最左元素一定被覆盖过，若没有，则表明右侧所有元素都&gt;x，那么算法将终止
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="n">s</span><span class="p">[</span><span class="n">j</span><span class="o">--</span><span class="p">]</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">x</span><span class="p">;</span>  <span class="c1">//i的位置放了x，所以其左侧都小于x，右侧y都大于x
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">return</span> <span class="n">i</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">quickSort</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">s</span><span class="p">,</span> <span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">//数组左界&lt;右界才有意义，否则说明都已排好，直接返回即可
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">if</span> <span class="p">(</span><span class="n">l</span> <span class="o">&gt;=</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// 划分，返回基准点位置
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">quickSortPartition</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">r</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// 递归处理左右两部分，i处为分界点，不用管i了
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">quickSort</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">quickSort</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">r</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">QuickSort</span><span class="p">(</span><span class="n">list_</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">list_</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">list_</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># 左边数组</span>
</span></span><span class="line"><span class="cl">    <span class="n">left</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># 右边数组</span>
</span></span><span class="line"><span class="cl">    <span class="n">right</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># 基准数</span>
</span></span><span class="line"><span class="cl">    <span class="n">base</span> <span class="o">=</span> <span class="n">list_</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># 对原数组进行划分</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">list_</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="n">base</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">left</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">right</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># 递归调用</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">QuickSort</span><span class="p">(</span><span class="n">left</span><span class="p">)</span> <span class="o">+</span> <span class="p">[</span><span class="n">base</span><span class="p">]</span> <span class="o">+</span> <span class="n">QuickSort</span><span class="p">(</span><span class="n">right</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">my</span> <span class="n">version</span> <span class="n">quicksort</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">quickSortPartition</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">s</span><span class="p">,</span> <span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">//Swap(s[l], s[(l + r) / 2]); //若以中间数为基准，则先将中间的这个数和第一个数交换即可
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">l</span><span class="p">,</span> <span class="n">j</span> <span class="o">=</span> <span class="n">r</span><span class="p">,</span> <span class="n">x</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="n">l</span><span class="p">];</span> <span class="c1">//将最左元素记录到x中
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">while</span> <span class="p">(</span><span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 从右向左找第一个&lt;x的数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="c1">// 无需考虑下标越界（有i的约束）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">while</span> <span class="p">(</span><span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span> <span class="o">&amp;&amp;</span> <span class="n">s</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="n">x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">j</span><span class="o">--</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 从左向右找第一个&gt;x的数
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">while</span> <span class="p">(</span><span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span> <span class="o">&amp;&amp;</span> <span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="n">x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">i</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">i</span> <span class="o">&lt;</span> <span class="n">j</span><span class="p">)</span> <span class="n">swap</span><span class="p">(</span><span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">s</span><span class="p">[</span><span class="n">j</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">swap</span><span class="p">(</span><span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">],</span><span class="n">s</span><span class="p">[</span><span class="n">l</span><span class="p">]);</span>  <span class="c1">//i,j的位置放了x，所以其左侧都小于x，右侧y都大于x,可以分析，当前的地方存放的一定是小于base的数字，所以直接和base进行一个交换，然后返回当前的坐标即可
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">return</span> <span class="n">i</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">quickSort</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">s</span><span class="p">,</span> <span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">//数组左界&lt;右界才有意义，否则说明都已排好，直接返回即可
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">if</span> <span class="p">(</span><span class="n">l</span> <span class="o">&gt;=</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// 划分，返回基准点位置
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">quickSortPartition</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">r</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// 递归处理左右两部分，i处为分界点，不用管i了
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">quickSort</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">quickSort</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">r</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="四-归并排序">四 归并排序</h4>
<ul>
<li>时间复杂度：归并排序主要分为拆分和对有序数组进行排序，拆分操作的时间复杂度为logn，排序的复杂度为n，所以归并排序的时间复杂度为O(nlogn)</li>
<li>归并排序的空间复杂度就是那个临时数组和递归时压如栈的数据占用的空间：n + logn，所以空间复杂度为O(n)</li>
</ul>
<p>(1)基本思想:归并（Merge）排序法是将两个（或两个以上）有序表合并成一个新的有序表，即把待排序序列分为若干个子序列，每个子序列是有序的。然后再把有序子序列合并为整体有序序列。归并排序中第二步，对两个有序数组排序法则非常简单，同时对两个数组的第一个位置比较大小，将小的放入一个空数组，然后被放入空数组的那个位置的指针往后移一个，然后继续和另一个数组的上一个位置进行比较，以此类推。直到最后任何一个数组先出栈完，就将另外一个数组里的所有元素追加到新数组后面。</p>
<p>​    归并排序和快速排序有那么点异曲同工之妙，快速排序：是先把数组粗略的排序成两个子数组，然后递归再粗略分两个子数组，直到子数组里面只有一个元素，那么就自然排好序了，可以总结为先排序再递归；归并排序：先什么都不管，把数组分为两个子数组，一直递归把数组划分为两个子数组，直到数组里只有一个元素，这时候才开始排序，让两个数组间排好序，依次按照递归的返回来把两个数组进行排好序，到最后就可以把整个数组排好序。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">_sort</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">,</span><span class="kt">int</span> <span class="n">a</span><span class="p">[],</span><span class="kt">int</span> <span class="n">l</span><span class="p">,</span><span class="kt">int</span> <span class="n">r</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">mid</span> <span class="o">=</span> <span class="p">(</span><span class="n">l</span><span class="o">+</span><span class="n">r</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">tem</span><span class="p">[</span><span class="n">n</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(</span><span class="n">l</span> <span class="o">==</span> <span class="n">r</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">_sort</span><span class="p">(</span><span class="n">n</span><span class="p">,</span><span class="n">a</span><span class="p">,</span><span class="n">l</span><span class="p">,</span><span class="n">mid</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">_sort</span><span class="p">(</span><span class="n">n</span><span class="p">,</span><span class="n">a</span><span class="p">,</span><span class="n">mid</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span><span class="n">r</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="c1">//归并，将l→mid 和 mid+1→r 两部分有序的数组归并成一个数组
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kt">int</span> <span class="n">la</span> <span class="o">=</span> <span class="n">l</span><span class="p">,</span><span class="n">lb</span> <span class="o">=</span> <span class="n">mid</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span><span class="kt">int</span> <span class="n">k</span><span class="o">=</span><span class="n">l</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span><span class="p">(</span><span class="n">la</span><span class="o">&lt;=</span><span class="n">mid</span> <span class="o">&amp;&amp;</span> <span class="n">lb</span><span class="o">&lt;=</span><span class="n">r</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span><span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="n">la</span><span class="p">]</span><span class="o">&lt;</span><span class="n">a</span><span class="p">[</span><span class="n">lb</span><span class="p">])</span> <span class="p">{</span> <span class="n">tem</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">a</span><span class="p">[</span><span class="n">la</span><span class="p">];</span><span class="n">k</span><span class="o">++</span><span class="p">;</span><span class="n">la</span><span class="o">++</span><span class="p">;}</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span>  <span class="p">{</span> <span class="n">tem</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">a</span><span class="p">[</span><span class="n">lb</span><span class="p">];</span><span class="n">k</span><span class="o">++</span><span class="p">;</span><span class="n">lb</span><span class="o">++</span><span class="p">;}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span><span class="p">(</span><span class="n">la</span><span class="o">&gt;</span><span class="n">mid</span> <span class="o">&amp;&amp;</span> <span class="n">lb</span><span class="o">&lt;=</span><span class="n">r</span><span class="p">){</span> <span class="n">tem</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">a</span><span class="p">[</span><span class="n">lb</span><span class="p">];</span><span class="n">k</span><span class="o">++</span><span class="p">;</span><span class="n">lb</span><span class="o">++</span><span class="p">;}</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span><span class="p">(</span><span class="n">lb</span><span class="o">&gt;</span><span class="n">r</span> <span class="o">&amp;&amp;</span> <span class="n">la</span><span class="o">&lt;=</span><span class="n">mid</span><span class="p">){</span> <span class="n">tem</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">a</span><span class="p">[</span><span class="n">la</span><span class="p">];</span><span class="n">k</span><span class="o">++</span><span class="p">;</span><span class="n">la</span><span class="o">++</span><span class="p">;}</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="n">l</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">r</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">tem</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="err">————————————————</span>
</span></span><span class="line"><span class="cl"><span class="err">版权声明：本文为</span><span class="n">CSDN博主</span><span class="err">「驰骋光束」的原创文章，遵循</span><span class="n">CC</span> <span class="mf">4.0</span> <span class="n">BY</span><span class="o">-</span><span class="n">SA版权协议</span><span class="err">，转载请附上原文出处链接及本声明。</span>
</span></span><span class="line"><span class="cl"><span class="err">原文链接：</span><span class="nl">https</span><span class="p">:</span><span class="c1">//blog.csdn.net/qq_37184747/article/details/72764628
</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="五-基数排序">五 基数排序</h4>
<h4 id="快排亲兄弟快速选择算法">快排亲兄弟：快速选择算法</h4>
<p><strong>数组中的第k个最大的元素</strong>：</p>
<ul>
<li>自己实现一个二叉堆，（优先队列）</li>
<li>使用快速查找的方法</li>
</ul>
<h3 id="各种数据结构的模拟编写">各种数据结构的模拟编写：</h3>
<ol start="5">
<li>红黑树？平衡树？B+树</li>
</ol>
<h5 id="hash-冲突解决的方法">hash 冲突解决的方法</h5>
<p>开放定址法、再hash法、链地址、公共溢出区</p>
<h5 id="stack栈队列的实现">Stack栈，队列的实现</h5>
<p>通过vector或者链表，维护一个头部的指针就行</p>
<p>队列也式类似的实现原理</p>
<h5 id="二叉堆">二叉堆</h5>
<p>通过vector和index*2的关系来实现，主要是一个插入和一个重排两部分算法</p>
<h5 id="hash的实现">Hash的实现</h5>
<p>待补充</p>
<h3 id="一些其他的问题">一些其他的问题</h3>
<h4 id="区间问题">区间问题</h4>
<p>也就是先使用排序，然后进行画图分析就行了；</p>
<p>其中986：区间有重叠区域的判断 b2&gt;a1 &amp;&amp; b1&gt;a2 （画图看看就知道了）</p>
<h4 id="计算器">计算器</h4>
<p>乘除法就使用和栈顶元素先结合，使用栈解决最终的加减法；括号进递归。</p>
<h4 id="随机算法">随机算法</h4>
<p>1/i 保留原有选择。</p>
<h4 id="差分数组和前缀和">差分数组和前缀和</h4>
<p>差分数组主要用于一段区域内的统一加减运算</p>
<h4 id="快速求素数">快速求素数</h4>
<p>从下往上搭建false表</p>
<h4 id="快速幂运算-模幂运算">快速幂运算 模幂运算</h4>
<p>这一题自己推导一下，然后自己写，印象更深</p>
<h4 id="判断括号的合法性">判断括号的合法性：</h4>
<ul>
<li>
<p>使用STACK，在出栈的时候进行匹配</p>
</li>
<li>
<p>如果带通配符的：双向进行查找，左到右的时候把*当成++ 右到左的时候也把*当成++,在遍历过程中只要小于0了就直接失效
这题实际上也可以使用DP，但是怎么做呢</p>
</li>
</ul>
<blockquote>
<p>状态转移：</p>
<p>算法：
如果且仅当间隔 s[i], s[i+1], &hellip;, s[j] 能组成有效的括号时，dp[i][j]为 true。只有在下列情况下，dp[i][j] 才为 true：</p>
<p>s[i] 是 &lsquo;*&rsquo; 号, 且在 s[i+1], s[i+2], &hellip;, s[j] 这个范围能够组成有效的括号
或者，s[i] 为 &lsquo;(&rsquo;，并且在 [i+1，j] 中有一些 k，使得 s[k] 为 &lsquo;)&rsquo;，且(s[i+1:k] 和 s[k+1:j+1])截断的两个间隔可以构成有效的括号；</p>
</blockquote>
<h4 id="批量判断是子序列还是字串">批量判断是子序列还是字串</h4>
<p>先统计出现的位置，然后针对位置进行二分搜索</p>
<h2 id="一些常用操作的复习">一些常用操作的复习</h2>
<p>LINUX：<a href="https://www.runoob.com/w3cnote/linux-common-command-2.html" target="_blank" rel="noopener">LINK1</a>
</p>
<p>GIT：Onenote</p>
<p>Docker：Markdown</p>

  </div>
</div>

<script>
    


function sanitizeContent(content) {
    
    return content.replace(/[\x00-\x1F\x7F]/g, '').trim(); 
}

function encryptContent(password, content) {
    const key = CryptoJS.MD5(password).toString();
    const iv = key.substring(16); 
    const paddedContent = padContent(content);
    const encrypted = CryptoJS.AES.encrypt(paddedContent, CryptoJS.enc.Utf8.parse(key), {
        iv: CryptoJS.enc.Utf8.parse(iv),
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
}

function padContent(content) {
    const blockSize = 32; 
    const padlen = blockSize - (content.length % blockSize);
    
    
    return content;
}

function processEncryptedBlocks() {
    const blocks = document.querySelectorAll('.hugo-encryptor-cipher-text');
    blocks.forEach(block => {
        const password = block.getAttribute('data-password');
        const content = block.innerHTML.trim(); 
        const sanitizedContent = sanitizeContent(content); 
        const encryptedContent = encryptContent(password, sanitizedContent);
        block.innerHTML = encryptedContent;
        block.removeAttribute('data-password');
    });

    
    const script = document.createElement('script');
    script.src = '/js/decrypt.js';
    document.body.appendChild(script);
}


document.addEventListener('DOMContentLoaded', processEncryptedBlocks);
</script>
]]></content:encoded>
    </item>
    <item>
      <title>Pooling</title>
      <link>https://aikenh.cn/posts/pooling/</link>
      <pubDate>Wed, 23 Jun 2021 13:48:56 +0000</pubDate>
      <guid>https://aikenh.cn/posts/pooling/</guid>
      <description>&lt;h1 id=&#34;downsamplingpooling的全面调研&#34;&gt;DownSampling：Pooling的全面调研&lt;/h1&gt;
&lt;p&gt;@Aiken 2021 笔记摘录：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://zhuanlan.zhihu.com/p/341820742&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;深度神经网络中的池化方法：全面调研（1989-2020） - 知乎&lt;/a&gt;
 ；&lt;a href=&#34;https://www.sohu.com/a/442710521_823210&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;相同论文的简单中文Version&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;16页综述，共计67篇参考文献。网络千奇百怪，但基础元素却大致相同！本文全面调研了1989至2020年一些著名且有用的池化方法，并主要对20种池化方法进行了详细介绍（这些方法，你都知道么？） 注1：文末附【计算机视…&lt;/p&gt;
&lt;p&gt;来自 &lt;a href=&#34;https://zhuanlan.zhihu.com/p/341820742&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://zhuanlan.zhihu.com/p/341820742&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;原文：《Pooling Methods in Deep Neural Networks, a Review》&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://zhuanlan.zhihu.com/p/112216409&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;整合2&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id=&#34;池化的根本目的motivation&#34;&gt;池化的根本目的（Motivation）&lt;/h2&gt;
&lt;p&gt;卷积神经网络是DNN的一种特殊类型，它由几个卷积层组成，每个卷积层后都有一个激活函数和一个池化层。&lt;/p&gt;
&lt;p&gt;池化层是重要的层，它对来自上一层的特征图执行下采样，并生成具有简化分辨率的新feature maps 。该层&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;p&gt;理想的池化方法应仅提取有用的信息，并丢弃无关的细节。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;特征不变性、特征降维、在一定程度上防止过拟合，更方便优化&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;主流的池化方法&#34;&gt;主流的池化方法&lt;/h2&gt;
&lt;h3 id=&#34;average-pooling-平均池化&#34;&gt;Average Pooling 平均池化&lt;/h3&gt;
&lt;p&gt;没啥好说的，就是每个block取一个均值。如下图所示：更关注全局特征&lt;/p&gt;
&lt;h3 id=&#34;max-pooling-最大值池化&#34;&gt;Max Pooling 最大值池化&lt;/h3&gt;
&lt;p&gt;更关注重要的局部特征&lt;/p&gt;
&lt;p&gt;
&lt;div class=&#34;post-img-view&#34;&gt;
  &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210219153154458.png&#34;&gt;
    &lt;img alt=&#34;https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210219153154458.png&#34; loading=&#34;lazy&#34; src=&#34;https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210219153154458.png&#34;class=&#34;responsive-image&#34; src=&#34;https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210219153154458.png&#34; style=&#34;display: block; margin: 0 auto;&#34;
      alt=&#34;https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210219153154458.png&#34;  /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;script&gt;
  document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
      var images = document.querySelectorAll(&#34;.responsive-image&#34;);
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + &#34;px&#34;;
      });
  });
&lt;/script&gt;
&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h1 id="downsamplingpooling的全面调研">DownSampling：Pooling的全面调研</h1>
<p>@Aiken 2021 笔记摘录：</p>
<p><a href="https://zhuanlan.zhihu.com/p/341820742" target="_blank" rel="noopener">深度神经网络中的池化方法：全面调研（1989-2020） - 知乎</a>
 ；<a href="https://www.sohu.com/a/442710521_823210" target="_blank" rel="noopener">相同论文的简单中文Version</a>
</p>
<p>16页综述，共计67篇参考文献。网络千奇百怪，但基础元素却大致相同！本文全面调研了1989至2020年一些著名且有用的池化方法，并主要对20种池化方法进行了详细介绍（这些方法，你都知道么？） 注1：文末附【计算机视…</p>
<p>来自 <a href="https://zhuanlan.zhihu.com/p/341820742" target="_blank" rel="noopener">https://zhuanlan.zhihu.com/p/341820742</a>
</p>
<p>原文：《Pooling Methods in Deep Neural Networks, a Review》</p>
<p><a href="https://zhuanlan.zhihu.com/p/112216409" target="_blank" rel="noopener">整合2</a>
</p>
<h2 id="池化的根本目的motivation">池化的根本目的（Motivation）</h2>
<p>卷积神经网络是DNN的一种特殊类型，它由几个卷积层组成，每个卷积层后都有一个激活函数和一个池化层。</p>
<p>池化层是重要的层，它对来自上一层的特征图执行下采样，并生成具有简化分辨率的新feature maps 。该层<strong>极大地减小了输入的空间尺寸</strong>。 它有两个主要目的。 首先是减少参数或权重的数量，从而减少计算成本。 第二是控制网络的过拟合。</p>
<ul>
<li>池化可以增加网络对于平移（旋转，伸缩）的不变性，提升网络的泛化能力。</li>
<li>增大感受野；</li>
<li>降低优化难度和参数数目，</li>
</ul>
<p>理想的池化方法应仅提取有用的信息，并丢弃无关的细节。</p>
<p><strong>特征不变性、特征降维、在一定程度上防止过拟合，更方便优化</strong></p>
<h2 id="主流的池化方法">主流的池化方法</h2>
<h3 id="average-pooling-平均池化">Average Pooling 平均池化</h3>
<p>没啥好说的，就是每个block取一个均值。如下图所示：更关注全局特征</p>
<h3 id="max-pooling-最大值池化">Max Pooling 最大值池化</h3>
<p>更关注重要的局部特征</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210219153154458.png">
    <img alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210219153154458.png" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210219153154458.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210219153154458.png" style="display: block; margin: 0 auto;"
      alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210219153154458.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>image-20210219153154458</p>
<h3 id="mixed-pooling">Mixed pooling</h3>
<p>在max、average pooling中进行随机选择，来组合pooling</p>
<h3 id="l_p-pooling">L_p pooling</h3>
<p>作者声称这个泛化能力比Max Pooling要好，输入的平均值权重（也就是和分之一）来进行，算是推广的公式。</p>
<div>
$$ 
s_j = (\\frac{1}{|R_j|}\\sum_{i \\in R_j}{a_i^p})^{1/p}
 $$
</div>
<h3 id="stochastic-pooling">Stochastic Pooling</h3>
<p>feature_map中的元素按照其概率值大小随机选择，元素被选中的概率与数值大小正相关，这就是正则化操作了。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210219160011182.png">
    <img alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210219160011182.png" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210219160011182.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210219160011182.png" style="display: block; margin: 0 auto;"
      alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210219160011182.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>image-20210219160011182</p>
<h3 id="spatial-pyramid-pooling-spp">Spatial Pyramid Pooling （SPP）</h3>
<p>SPPNet在RCNN之后提出的，用于解决重复卷积计算和固定输出的问题，具体的方法是：在Feature_Map中通过Selective Search获得窗口然后输入CNN中。</p>
<p>这个池化方法实际上就是多个空间池化的组合，对不同的输出尺度采用不同的划窗大小和步长<strong>来确保输出的尺度相同</strong>，同时能够融合多种尺度特征，提供更丰富的语意信息，常用于：</p>
<ul>
<li>多尺度训练</li>
<li>目标检测中的RPN</li>
</ul>
<p>实际上也就是（全图pooling一次，全图分成2<em>2块Pooling，全图分成4</em>4块以后 做Pooling，然后就是固定尺寸的了，前面的输出是256-d 然后就是（4+16+1）* 256 最后的特征</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210219160238878.png">
    <img alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210219160238878.png" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210219160238878.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210219160238878.png" style="display: block; margin: 0 auto;"
      alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210219160238878.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>image-20210219160238878</p>
<h3 id="yolo-v3-变体">YOLO v3 变体</h3>
<p>在YOLO v3中，有一个网络结构中的yolo-v3-spp比原本的准确率更高，具体的cfg如下：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span></span>
    </div>
    <div class="code-content">
        
        <pre tabindex="0"><code>### SPP ###
[maxpool]
stride=1
size=5

[route]
layers=-2

[maxpool]
stride=1
size=9

[route]
layers=-4

[maxpool]
stride=1
size=13

[route]
layers=-1,-3,-5,-6

### End SPP ###</code></pre>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>这里的SPP是原本的SPPNet的变体，通过多个Kernel Size的maxpool 将最终得到的feature map进行concate，得到新的特征组合：</p>
<h3 id="spp有效的原因分析">SPP有效的原因分析</h3>
<ol>
<li>
<p>从感受野角度来讲，之前计算感受野的时候可以明显发现，maxpool的操作对感受野的影响非常大，其中主要取决于kernel size大小。在SPP中，使用了kernel size非常大的maxpool会极大提高模型的感受野，笔者没有详细计算过darknet53这个backbone的感受野，在COCO上有效很可能是因为backbone的感受野还不够大。</p>
</li>
<li>
<p>第二个角度是从Attention的角度考虑，这一点启发自CSDN@小楞（链接在参考文献中），他在文章中这样讲：</p>
<blockquote>
<p>出现检测效果提升的原因：通过spp模块实现局部特征和全局特征（所以空间金字塔池化结构的最大的池化核要尽可能的接近等于需要池化的featherMap的大小）的featherMap级别的融合，丰富最终特征图的表达能力，从而提高MAP。</p>
</blockquote>
</li>
<li>
<p>Attention机制很多都是为了解决远距离依赖问题，通过使用kernel size接近特征图的size可以以比较小的计算代价解决这个问题。另外就是如果使用了SPP模块，就没有必要在SPP后继续使用其他空间注意力模块比如SK block，因为他们作用相似，可能会有一定冗余。</p>
</li>
</ol>
<h3 id="region-of-interest-pooling-roi-pooling">Region of Interest Pooling （ROI Pooling）</h3>
<p>参考链接：<a href="https://blog.csdn.net/u011436429/article/details/80279536" target="_blank" rel="noopener">原理以及代码实现</a>
；<a href="https://zhuanlan.zhihu.com/p/59692298" target="_blank" rel="noopener">Some Detail 以及Align的改进</a>
；<a href="https://www.sohu.com/a/414474326_823210" target="_blank" rel="noopener">Best One</a>
</p>
<p>对于ROI pooling 的讲解首先要从目标检测的框架出发，帮助理解，</p>
<p>目标检测分为两步：</p>
<ol>
<li>region proposal：输入image，找到所有可能的object的位置（bounding box），也就是ROI，在这过程中可能用到滑窗和selective search。</li>
<li>final classification：确定上阶段的每个region proposal是否是目标类别，或者背景</li>
</ol>
<p>这样的框架<strong>存在问题：</strong></p>
<ul>
<li>大量的ROI要进行计算，就很难实时监测，也无法做到E2E</li>
</ul>
<p>使用ROI Pooling进行简化，<strong>输入和作用</strong>如下：</p>
<ul>
<li>从多个具有卷积核池化的深度网络中获得固定大小的Feature-Map；
对不同尺寸的ROI进行处理，能得到统一的尺寸。</li>
<li>一个表示所有ROI的N*5的尺寸，N是数目，5维度分别是Index，左上角坐标，右下角坐标</li>
</ul>
<p>具体实现的操作：</p>
<ol>
<li>根据输入image，将ROI映射到feature map对应位置；</li>
<li>将映射后的区域划分为相同大小的sections（sections数量与输出的维度相同）；</li>
<li>对每个sections进行max pooling操作；</li>
</ol>
<p>这样我们就可以从不同大小的方框得到固定大小的相应 的feature maps。值得一提的是，输出的feature maps的大小不取决于ROI和卷积feature maps大小。ROI pooling 最大的好处就在于极大地提高了处理速度。</p>
<p>下图大黑框是对应的ROI，输出最后的要求是2*2，基于下面的划分再进行maxpooling即可。</p>
<h3 id="roi-align的改进">ROI Align的改进</h3>
<p>ROI pooling在映射的时候出现小数，这是第一次量化，在每个roi中选取多少个采样点进行max pooling也会出现小数。这样的处理可能会丢失数据，降低了模型的精度</p>
<p>ROI Align并不需要对两步量化中产生的浮点数坐标的像素值都进行计算，而是设计了一套优雅的流程。如图2，其中虚线代表的是一个feature map，实线代表的是一个roi(在这个例子中，一个roi是分成了2*2个bins)，实心点代表的是采样点，每个bin中有4个采样点。我们通过双线性插值的方法根据采样点周围的四个点计算每一个采样点的值，然后对着四个采样点执行最大池化操作得到当前bin的像素值。</p>
<p>**RoI Align做法：**假定采样点数为4，即表示，对于每个2.97 x 2.97的bin，<strong>平分四份小矩形，每一份取其中心点位置，而中心点位置的像素，采用双线性插值法进行计算</strong>，这样就会得到四个小数坐标点的像素值。</p>
<p>实际上就是用双线性插值来取代了ROI Pooling的量化过程。</p>
<h2 id="新颖特殊的池化方法">新颖特殊的池化方法</h2>
<p>这一部分的池化方法存在着一些特殊的特性，在实际需要的时候再进行仔细的研究，但是可以将大体的特征简单的描述一下，方便后续寻找。</p>
<h3 id="中值池化">中值池化</h3>
<p>与中值滤波特别类似，但是用的特别少，中值池化也具有学习边缘和纹理结构的特性，抗噪声能力比较强。</p>
<h3 id="组合池化">组合池化</h3>
<p>就是将max 和 average concate或者add起来。</p>
<h3 id="multi-scale-order-less-pooling-mop池化">Multi-scale order-less Pooling MOP池化</h3>
<p>基于多尺度的池化方式，提升了卷积网络的不变性同时没有破坏卷积网络的可鉴别性，分布从全局与局部池化中提取特征，图示与说明如下：</p>
<h3 id="netvlad-pooling">NetVLAD Pooling</h3>
<p>NetVLAD是论文《NetVLAD: CNN Architecture for Weakly Supervised Place Recognition》提出的一个局部特征聚合的方法。</p>
<h3 id="双线性池化">双线性池化</h3>
<p>Bilinear Pooling是在《Bilinear CNN Models for Fine-grained Visual Recognition》被提出的，主要用在细粒度分类网络中。双线性池化主要用于特征融合，对于同一个样本提取得到的特征x和特征y, 通过双线性池化来融合两个特征(外积)，进而提高模型分类的能力。</p>
<h3 id="unpooling上采样操作">UnPooling上采样操作</h3>
<p>1.在Pooling（一般是Max Pooling）时，保存最大值的位置。</p>
<p>2.中间经历若干网络层的运算。</p>
<p>3.上采样阶段，利用第1步保存的Max Location，重建下一层的feature map。</p>
<blockquote>
<p><strong>UnPooling不完全是Pooling的逆运算</strong>，Pooling之后的feature map，要经过若干运算，才会进行UnPooling操作；对于非Max Location的地方以零填充。然而这样并不能完全还原信息。</p>
</blockquote>
<h3 id="光谱池化">光谱池化</h3>
<p>图像池化不光发生在空间域，<strong>还可以通过DFT变换，在频域空间实现池化</strong>，一个使用光谱池化最大池化的例子如下：</p>
<h3 id="基于排名的均值池化">基于排名的均值池化</h3>
<p><strong>Rank-based Average Pooling</strong></p>
<p>这种池化方式的好处事可以克服最大池化与均值池化方式的不足</p>
<div>
$$ 
S_j = \\frac{1}{t}\\sum_{i\\in R_{j,r_i<t}} a_i
 $$
</div>
<h3 id="基于权重的池化">基于权重的池化</h3>
<h3 id="edge-aware-pyramid-pooling">Edge-aware Pyramid Pooling</h3>
<p><a href="Pooling%20b5b6c37730b54ff89114750889d54aec/Survey_NIPS%20%E4%B8%AD%E5%9B%BD%E9%A2%84%E8%AE%B2%E4%BC%9A%20md%20a89f987a08854a2c9c2fb44213136246.md">Survey_NIPS 中国预讲会.md</a>
</p>
]]></content:encoded>
    </item>
    <item>
      <title>OW-openmix</title>
      <link>https://aikenh.cn/posts/ow-openmix/</link>
      <pubDate>Wed, 23 Jun 2021 13:45:50 +0000</pubDate>
      <guid>https://aikenh.cn/posts/ow-openmix/</guid>
      <description>Reviving Known Knowledge for Discovering Novel Visual Categories in An Open World</description>
      <content:encoded><![CDATA[<p>@Aiken 2021 究极万恶的撞车论文</p>
<h2 id="intro">Intro</h2>
<p><strong>Motivation</strong> ：Tackle the problem of 发现无标注数据中与给定（已知）类别不相交的新类。</p>
<p><strong>Related Research：</strong></p>
<p>现有的方法通常1. 使用标记数据对模型进行预训练； 2. 无监督聚类在未标记的数据中识别新的类</p>
<blockquote>
<p>作者认为label带来的essential knowledge在第二步中没有被充分学习利用到，这样模型就只能从第一步的现成知识中获益，而不能利用标记数据和未标记数据之间的潜在关系</p>
</blockquote>
<p><strong>Hypothesis：</strong></p>
<p>有标记的类别和无标记的类别之间没有Overlap，这样导致在两个类别之间很难建立学习关系，（为啥我感觉这个说的都是屁话）</p>
<p><strong>Solution：</strong></p>
<p>Openmix：将标注的数据和未标注的数据同时混合起来得到一个联合标签的分布中，用两种方式来动态合成示例：</p>
<ol>
<li>我们混合标记和未标记数据作为Training Img，混合了已知类别的先验生成的伪标签会比无监督情况下生成的伪标签跟家的可靠？防止在错误的伪标签前提下发生过拟合</li>
<li>在第一步的时候我们鼓励具有高类别置信度的无标记example作为可考虑的类别，然后我们将这些samples作为anchor，并将它们进一步的和无标注的samples整合，这使得我们能够对无标注数据产生更多的组合，并发现更精细的新类关系。</li>
</ol>
<h2 id="detail">Detail</h2>
<p>果然在混合的方式上和MixUp的策略进行比对了，就是diss了Mixup使用伪标签的情景可能会进一步的引入不确定性，导致算法的效果反向优化，就是再label和unlabeled数据上混用mixup，而不是单纯的对unlabel数据集进行混合。</p>
<p>首先将没有overlap的标签表现为联合标签分布再进行混合，也就是加长onehot，这样的标签的优越性在？对于unlabelled data引入了确定性，防止标签容易过拟合。也就是给伪标签加入了一个锚定，让他能够变化的更平滑</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210414225637547.png">
    <img alt="image-20210414225637547" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210414225637547.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210414225637547.png" style="display: block; margin: 0 auto;"
      alt="image-20210414225637547"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>这尼玛这张图看了不久完事了，bibi一大堆啥的呢。主要分析一下三个损失函数代表的是什么意思。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210414231455696.png">
    <img alt="image-20210414231455696" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210414231455696.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210414231455696.png" style="display: block; margin: 0 auto;"
      alt="image-20210414231455696"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<img src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210415164800451.png" alt="image-20210415164800451" style="zoom: 50%;" />
<p>对其中的 $L_{ppl}$ 进行特殊的说明：</p>
<ul>
<li>由于输入的是pair，所以添加的一个损失也就是分类是否属于同一类，二分类ce</li>
<li>使用的是cos similarity，通过threshold 来判断是否是同一类，</li>
<li>实际上应该也是一个预训练的模块，在实际进行的过程中由于是对无标注数据进行处理，讲道理是无法计算损失的，也没有开源代码。</li>
</ul>
<h2 id="异同点分析">异同点分析</h2>
<p>初步分析结果：</p>
<ol>
<li>不使用无监督聚类的方法对新类进行发现，而是使用其他的策略</li>
<li>好像没有使用增量学习的方法进行class-incremental的增量处理，主要的motivation好像是Discovering，并没有Incremental的部分</li>
<li>新数据的组合方式是怎么样的这点好像值得研究一下</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>Reward is Enough</title>
      <link>https://aikenh.cn/posts/rl-reward_is_enough/</link>
      <pubDate>Sun, 06 Jun 2021 13:53:36 +0000</pubDate>
      <guid>https://aikenh.cn/posts/rl-reward_is_enough/</guid>
      <description>&lt;p&gt;Desc: RL
Finished?: Yes
Tags: Paper&lt;/p&gt;
&lt;p&gt;通用人工智能，是否能通过强化学习的奖励机制就实现&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://mp.weixin.qq.com/s/XTNyLjZ9KfdtHY4Omb9_4w&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;实现AGI，强化学习就够了？Sutton、Silver师徒联手：奖励机制足够实现各种目标&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id=&#34;对reward构建agi的可行性的分析和探讨&#34;&gt;对reward构建AGI的可行性的分析和探讨&lt;/h2&gt;
&lt;p&gt;这篇文章实际上没有给出一个很好的方案通过reward来实现各种AGI的设计，但是给出了在每一种场景下的AGI的reward设计的设想把。和对用reward进行设计的可行性分析。
同时分析了：感知、社交、语言、泛化、模仿，这几个方面&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;类似地，如果人工智能体的经验流足够丰富，那么单一目标（例如电池寿命或生存）可能隐含地需要实现同样广泛的子目标的能力，因此奖励最大化应该足以产生一种通用人工智能。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这不久回到了最基础的问题，没有这种长线以及大量数据交互以及全面场景的经验流，来支撑这样一个AGI的学习，所以这不也是在现阶段上纸上谈兵嘛？&lt;/p&gt;
&lt;p&gt;对这篇论文我的总结是，我不推荐详细阅读，我觉得收益有限，太理想化，其实和强化学习本身的假设也没有太多新东西，我们可以假设强化学习能带来一个AGI，但是对应的约束和限制确实是有点多了。&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Desc: RL
Finished?: Yes
Tags: Paper</p>
<p>通用人工智能，是否能通过强化学习的奖励机制就实现</p>
<p><a href="https://mp.weixin.qq.com/s/XTNyLjZ9KfdtHY4Omb9_4w" target="_blank" rel="noopener">实现AGI，强化学习就够了？Sutton、Silver师徒联手：奖励机制足够实现各种目标</a>
</p>
<h2 id="对reward构建agi的可行性的分析和探讨">对reward构建AGI的可行性的分析和探讨</h2>
<p>这篇文章实际上没有给出一个很好的方案通过reward来实现各种AGI的设计，但是给出了在每一种场景下的AGI的reward设计的设想把。和对用reward进行设计的可行性分析。
同时分析了：感知、社交、语言、泛化、模仿，这几个方面</p>
<blockquote>
<p>类似地，如果人工智能体的经验流足够丰富，那么单一目标（例如电池寿命或生存）可能隐含地需要实现同样广泛的子目标的能力，因此奖励最大化应该足以产生一种通用人工智能。</p>
</blockquote>
<p>这不久回到了最基础的问题，没有这种长线以及大量数据交互以及全面场景的经验流，来支撑这样一个AGI的学习，所以这不也是在现阶段上纸上谈兵嘛？</p>
<p>对这篇论文我的总结是，我不推荐详细阅读，我觉得收益有限，太理想化，其实和强化学习本身的假设也没有太多新东西，我们可以假设强化学习能带来一个AGI，但是对应的约束和限制确实是有点多了。</p>
]]></content:encoded>
    </item>
    <item>
      <title>RL-MobaAI</title>
      <link>https://aikenh.cn/posts/rl-mobaai_tencent/</link>
      <pubDate>Sun, 30 May 2021 13:52:42 +0000</pubDate>
      <guid>https://aikenh.cn/posts/rl-mobaai_tencent/</guid>
      <description>腾讯绝悟</description>
      <content:encoded><![CDATA[<p>Created by: Aiken H
Desc: GAME, RL
Finished?: Yes
Tags: Paper</p>
<p>《Master Complex Control in MOBA Games with Deep Reinforcement Learning》 论文阅读笔记</p>
<p>@Aiken H 2021.06</p>
<h2 id="introduction-and-related-research">Introduction and Related Research.</h2>
<p>MOBA游戏的复杂度和状态空间都远比以前的围棋之类的运动更大，所以难度会更大一些</p>
<p>早一些的游戏ai使用的是（2015） Deep Q-Network  通过 supervised learning and self-play 结合的训练策略在围棋上击败了专业人类，而最近更多的使用了DRL（Deep Reinforcement Learning）的方法在近几年被进一步的应用。</p>
<h3 id="neural-network-architecture-include"><strong>Neural Network Architecture Include</strong></h3>
<h3 id="contributions"><strong>Contributions</strong></h3>
<ul>
<li>the <strong>encoding</strong> of <strong>Multi-modal inputs 多模态输入</strong></li>
<li>the <strong>decoupling</strong> of inter-correlations in controls <strong>控制内关联解码</strong></li>
<li>exploration <strong>pruning</strong> mechanism  <strong>剪枝设置</strong></li>
<li><strong>Action mask</strong> for efficient exploration ❓<strong>效率</strong></li>
<li>attack <strong>attention</strong>(for target selection) <strong>Attention机制做目标选择</strong></li>
<li><strong>LSTM</strong> for learning skill combos <strong>LSTM 机制做技能释放和链接</strong></li>
<li><strong>Optimize</strong> by multi-label proximal policy algorithm(<strong>improved PPO</strong>)
<ul>
<li>dual-clip PPO 帮助训练的收敛</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li>
<p>present a systematic and thorough study</p>
</li>
<li>
<p>develop a deep reinforcement learning framework which provides scalable and off-policy training</p>
</li>
<li>
<p>we develop an actor-critic neural network</p>
<p>跳转上面的网络架构</p>
</li>
</ul>
<h2 id="framework-design">Framework Design</h2>
<p><strong>(S.O.A.P, $\gamma$ , $\tau$ , $\rho_0$ ) to denote infinite-horizon ： 使用元组去模拟整个动态强化的过程,过程主要的是最大化累计reward</strong></p>
<p>S 状态空间  O 观察状态空间  A 动作空间 $\rho_0$ 初始状态分布 $\gamma$  折扣系数</p>
<p>目标MAX： $\mathbb{E}[\sum_{t = 0}^{T} \gamma^t \tau(s_t,\alpha_t)]$</p>
<p>$\tau: S \times A \rightarrow \mathbb{R}$ 奖励函数</p>
<p>$\pi： O \times A \rightarrow [0,1]$ 策略</p>
<p>$P:S\times A \rightarrow S$ 状态转移分布</p>
<p><strong>SUMMARY: This Part is about the basic rule of the RL setting.</strong></p>
<h2 id="system-design">System Design</h2>
<p>The whole system and workflow design will be shown on this part</p>
<p>由于MOBA游戏复杂的Agent（Players和Characters） 会带来高方差的随机梯度，所以再这种模型的训练中，我们可能会需要一个大的Batach Size来防止Invariant Shift的这种现象，同时并加速训练的有效和收敛性。于是我们设计了一个规模可变，弱耦合的网络架构。</p>
<p>模型整体由四个部分组成：RL-Learner、AI-Server、Dispatch-Module（调度）、Memory-Pool（记忆池）</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210606200814983.png">
    <img alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210606200814983.png" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210606200814983.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210606200814983.png" style="display: block; margin: 0 auto;"
      alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210606200814983.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ul>
<li>AI-Server:：与环境进行交互模拟（self-play）</li>
<li>RL Learning：核心学习网络</li>
<li>Memory Pool：数据存储，为RL提供训练和搜索的实例</li>
<li>Dispatch：数据的收集，压缩，传输</li>
<li>模块之间相互解耦，可以灵活配置，</li>
</ul>
<h2 id="module-detail">Module Detail</h2>
<h3 id="ai-server">AI-Server</h3>
<ul>
<li>传统策略：提供了游戏环境和AI模型之间的交互逻辑，通过相互镜像的策略来进行self-play，从而生成episodes.</li>
<li>对手策略：基于游戏状态中提取的特征使用玻尔兹曼搜索，预测英雄行文（基于softmax的分布采样，发送给CPU执行），返回reward和下一个state</li>
<li>CPU版本的FeatherCNN，转换到LOCAL上进行inference</li>
</ul>
<h3 id="dispatch-module">Dispatch Module</h3>
<ul>
<li>和多个AI-Service绑定，是一个收集数据样本的服务器，主要包括：奖励，特征，动作概率等</li>
<li>将这些数据压缩和打包，然后发到内存池中</li>
</ul>
<h3 id="memory-pool">Memory Pool</h3>
<ul>
<li>服务器：内部实现为用于数据存储的内存高效循环队列</li>
<li>支持不同长度的样本，以及基于生成时间的数据采样</li>
</ul>
<h3 id="rl-learner">RL Learner</h3>
<ul>
<li>分布式训练环境，为了使用Big Batch，使用多个RL Learner并行的从Memory Pool 获取数据，然后通过ring allreduce算法来集成梯度</li>
<li>通过共享内存（而不是socket）和pool来进行数据交换，从而减少IO需求</li>
<li>P2P的在策略更新和AI service进行快速同步</li>
</ul>
<p><strong>SUMMARY: 经验生成和参数学习是分离的，以及Memory和Dispath的架构，能够使得算法能够很容易的拓展到百万歌CPU内核和数千个GPU。</strong></p>
<h2 id="algorithm-design">Algorithm Design</h2>
<p>An <strong>Actor-Critic</strong> Network 用来建模游戏中的动作依赖关系</p>
<h3 id="网络架构">网络架构</h3>
<p>由下图说明了网络的状态和动作，为了有效的训练这个网络，提出了一些新颖的策略：目标注意力机制（选择目标）；LSTM用来学习技能combo，和动作选择；控制依赖解耦来建立一个PPO；（先验引入）基于游戏知识的剪枝（Action mask）；优化PPO成dual-clipped PPO 保证大批次和大偏差的收敛性</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210606222810882.png">
    <img alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210606222810882.png" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210606222810882.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210606222810882.png" style="display: block; margin: 0 auto;"
      alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210606222810882.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>对图像、Unit、GameInfo分别提取特征后整合成固定长度的Feature，通过LSTM（考虑时间维度的表征）得到最终的表征，然后通过FC对特征进行分类解码（也可以说是预测把），同时基于状态编码的注意力机制来整合出对象预测，</p>
<div>
$$ 目标注意力：p(t|a) = Softmax(FC(h_{LSTM}·h_{key}^T) $$
</div>
<ul>
<li>p(t|a)是units上的注意力分布，维度是状态中的单元数。</li>
<li>为了解决多标签策略网络中，同一个动作不同标签之间的关联显示建模困难的问题，独立处理一个动作中的每个标签解耦他们的相互关联。</li>
</ul>
<p>原始的PPO objective：E:有限批次的经验平均值，其余的参见上面的对照表</p>
<div>
$$ \max_{\theta} \hat{\mathbb{E}}_{s\sim \pi_{\theta_{old}}}[\frac{\pi_{\theta}(a_t|s_t)}{\pi_{\theta_{old}}(a_t|s_t)}]\hat{A_t} $$
</div>
<p>参数解耦之后可以看到：</p>
<div>
$$ \max_{\theta}\sum_{i=0}^{N_a-1} \hat{\mathbb{E}}_{s\sim \pi_{\theta_{old}}}[\frac{\pi_{\theta}(a_t^i|s_t)}{\pi_{\theta_{old}}(a_t^i|s_t)}]\hat{A_t} $$
</div>
<p>有两个优点：简化策略的结构（不考虑相关性）；增加策略的多样性，为了多样性，我们开始的训练过程中，随机了初始化agent的位置。</p>
<p>缺点：进一步增加的策略训练的复杂度，所以通过action mask来进行简化，在最终输出层来合并动作元素之间的相关性，从而修建需要的策略搜索空间，</p>
<h3 id="dual-clip-ppo">Dual-clip PPO</h3>
<p>令 $\tau_t(\theta) = [\frac{\pi_{\theta}(a_t|s_t)}{\pi_{\theta_{old}}(a_t|s_t)}]$ ,由于这个值可能会很大，导致过大的策略偏差，为了缓解这个问题，我们引入</p>
<div>
$$ L^{CLIP}(\theta)\hat{\mathbb{E}}_t[\min(\tau_t(\theta)\hat{A_t},clip(\tau_t(\theta),1-\epsilon,1+\epsilon)\hat{A_t})] $$
</div>
<p>来惩罚政策的极端变化，但是另一种情况下的极端值也会带来无界偏差，所以还有另一端的优化,其中c&gt;1是一个下线常数</p>
<div>
$$ \hat{\mathbb{E}_t}[\max(\min(\tau_t(\theta)\hat{A_t},clip(\tau_t(\theta),1-\epsilon,1+\epsilon)\hat{A_t}),c\hat{A_t})] $$
</div>]]></content:encoded>
    </item>
    <item>
      <title>RL Notebook 01</title>
      <link>https://aikenh.cn/posts/rl-c1/</link>
      <pubDate>Sun, 23 May 2021 13:50:06 +0000</pubDate>
      <guid>https://aikenh.cn/posts/rl-c1/</guid>
      <description>Reinforcement learning Notebook 01</description>
      <content:encoded><![CDATA[<p>Created by: Aiken H
Detail: survey
Finished?: No
Tags: Paper
URL1: <a href="https://www.cnblogs.com/pinard/category/1254674.html" target="_blank" rel="noopener">https://www.cnblogs.com/pinard/category/1254674.html</a>

URL2: <a href="https://github.com/ljpzzz/machinelearning" target="_blank" rel="noopener">https://github.com/ljpzzz/machinelearning</a>

URL3: <a href="https://datawhalechina.github.io/easy-rl/#/" target="_blank" rel="noopener">https://datawhalechina.github.io/easy-rl/#/</a>
</p>
<h1 id="chapter1-模型基础">Chapter1 模型基础</h1>
<p><a href="https://www.cnblogs.com/pinard/p/9385570.html" target="_blank" rel="noopener">强化学习（一）模型基础</a>
</p>
<p>强化学习是介于监督和无监督学习之间的，强化学习没有输出值，但是有<strong>reward：</strong> 同时这个reward是事后给出的，而不是及时回馈的。而无监督学习是只有数据特征，同时数据之间是独立的，没有前后依赖的关系。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911210000.png">
    <img alt="https://images2018.cnblogs.com/blog/1042406/201807/1042406-20180729163058011-290427357.png" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911210000.png"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911210000.png" style="display: block; margin: 0 auto;"
      alt="https://images2018.cnblogs.com/blog/1042406/201807/1042406-20180729163058011-290427357.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h2 id="theory理论基础">Theory理论基础</h2>
<ul>
<li>
<p>简化模型介绍：</p>
<p>上面的大脑代表我们的算法执行个体，我们可以操作个体来做决策，即选择一个合适的动作（Action）At。下面的地球代表我们要研究的环境,它有自己的状态模型，我们选择了动作At后，环境的状态(State)会变，我们会发现环境状态已经变为St+1,同时我们得到了我们采取动作At的延时奖励(Reward)Rt+1。然后个体可以继续选择下一个合适的动作，然后环境的状态又会变，又有新的奖励值。。。这就是强化学习的思路。</p>
</li>
</ul>
<p>强化学习的模型关键要素：</p>
<ol>
<li>环境的状态S：t时刻环境的状态 $S_t$ 是它环境状态集中的某一个状态</li>
<li>个体的动作A：个体在某个时刻可能做出的动作集合</li>
<li>环境的奖励R：个体在某个时刻对应状态下做出的动作 $A_t$ 得到的奖励会在t+1时刻得到</li>
<li>个体的策略 $\pi$ ：个体根据当前的环境选择采取动作的策略分布（函数），一般表示为一个条件概率分布的形式，概率大的动作被个体选择的概率显然更高</li>
</ol>
<div>
$$ \pi(a|s)= P(A_t = a | S_t = s) $$
</div>
<ol start="5">
<li>在策略 $\pi$ 和状态s采行动后的价值 $v_\pi(s)$ ：一般是一个期望函数，因为我们不能每次只能选择当前的reward最大的策略，而是需要考虑大局，所以我们要有一个综合的（当前和后续）的延时奖励。</li>
</ol>
<div>
$$ v_\pi(s) = \mathbb{E}(R_{t+1} + \gamma R_{t+2} + \gamma ^2 R_{t+3} + ... |S_t = s) $$
</div>
<ol start="6">
<li>奖励衰减因子 $\gamma$ ：也就是上式的权重，极端值考虑贪婪和一致等同，范围在[0,1]</li>
<li>环境的状态转移模型：也就是环境从s经过a后转化下一个状态的状态机，也可以表示为一个概率模型 $P_{ss^‘}^a$ (s→s&rsquo; , a)</li>
<li>探索率 $\epsilon$ ：主要用于训练迭代中，我们一般选择当前价值最大的动作，但是为了搜索空间的完备，我们会用 $\epsilon$ 的概率去选择非最大价值的动作，来提升训练的鲁棒性</li>
</ol>
<p><strong>SUMMARY：主要介绍了强化学习模型的workflow以及其中需要考虑的8个主要参数和函数架构。最主要的机制还是Policy和reward设计这一块</strong></p>
<h1 id="chapter2-马尔可夫决策过程mdp">Chapter2 马尔可夫决策过程（MDP）</h1>
<p><a href="https://www.cnblogs.com/pinard/p/9426283.html" target="_blank" rel="noopener">强化学习（二）马尔科夫决策过程(MDP)</a>
</p>
<p><a href="https://datawhalechina.github.io/easy-rl/#/chapter2/chapter2" target="_blank" rel="noopener">Easy-RL</a>
</p>
<p>在这里可能需要补充一下马尔可夫链的相关理论知识，先粗略的看完这部分再说</p>
<h2 id="马尔可夫性简化">马尔可夫性简化</h2>
<p>环境的真实转化状态可能和之前的多个时刻相关，这样会导致建模困难，于是我们对环境的状态转移模型进行马尔可夫性假设。也就是：</p>
<p>转化到下一个状态s&rsquo;只和当前的状态s相关，与之前的状态无关</p>
<p>同样的我们对Policy、价值函数也做了同样的马尔可夫性假设来简化。</p>
<p>其中： $G_t$ 代表收获（return），是从某一个状态开始采样直到终止状态时所有奖励的有衰减的和。</p>
<div>
$$ 1.\ P_{ss'}^a = \mathbb{E}(S_{t+1} = s'|S_t=s,A_t=a) $$
</div>
<div>
$$ 2. \ \pi(a|s) = P(A_t = a | S_t = s) $$
</div>
<div>
$$ 3. \ v_\pi(s) =\mathbb{E}_\pi(G_t|S_t =s) = \mathbb{E}(R_{t+1} + \gamma R_{t+2} + \gamma ^2 R_{t+3} + ... |S_t = s) $$
</div>
<p><strong>SUMMARY：由于环境的复杂时序关系，我们需要进行相应的马尔可夫性的假设，让下一个时刻的状态或者预测值只和当前时刻有关，从而简化并假设出模型</strong></p>
<h2 id="mdp的价值函数和贝尔曼方程">MDP的价值函数和贝尔曼方程</h2>
<p>在上述价值表达式的基础上，加入考虑动作a带来的价值影响，我们就可以得到下面的动作价值函数：</p>
<div>
$$ q_{\pi}(s, a)=\mathbb{E}_{\pi}\left(G_{t} \mid S_{t}=s, A_{t}=a\right)=\mathbb{E}_{\pi}\left(R_{t+1}+\gamma R_{t+2}+\gamma^{2} R_{t+3}+\ldots \mid S_{t}=s, A_{t}=a\right) $$
</div>
<p>我们可以通过价值函数的公式得到价值函数的递推关系（贝尔曼方程）：</p>
<div>
$$ \begin{aligned}
v_{\pi}(s) &=\mathbb{E}{\pi}\left(R{t+1}+\gamma R_{t+2}+\gamma^{2} R_{t+3}+\ldots \mid S_{t}=s\right) \\
&=\mathbb{E}{\pi}\left(R{t+1}+\gamma\left(R_{t+2}+\gamma R_{t+3}+\ldots\right) \mid S_{t}=s\right) \\
&=\mathbb{E}{\pi}\left(R{t+1}+\gamma G_{t+1} \mid S_{t}=s\right) \\
&=\mathbb{E}{\pi}\left(R{t+1}+\gamma v_{\pi}\left(S_{t+1}\right) \mid S_{t}=s\right)
\end{aligned} $$
</div>
<p>一个状态的价值由该状态的奖励以及后续状态价值按照一定衰减比例联合而成，同样的有：</p>
<div>
$$ q_{\pi}(s, a)=\mathbb{E}_{\pi}\left(R_{t+1}+\gamma q_{\pi}\left(S_{t+1}, A_{t+1}\right) \mid S_{t}=s, A_{t}=a\right) $$
</div>
<p>SUMMARY：基于马尔可夫假设之后，我们可以将价值函数（动作、状态）表示一个递推的形式，这个递推的形式也被叫做贝尔曼方程。</p>
<h2 id="状态价值函数和动作价值函数的递推关系">状态价值函数和动作价值函数的递推关系</h2>
<p>基于状态价值函数的定义以及动作价值函数的定义，我们很容易得到两个价值函数之间的转化关系：</p>
<p>状态价值函数是动作价值函数对于所有可能动作对于policy的期望。</p>
<p>利用贝尔曼方程，我们也能反推得状态价值函数来表示动作价值函数：</p>
<p>当前的reward和可能转移到所有后续状态的价值函数的加权和</p>
<div>
$$ v_\pi(s) = \sum_{a\in A} \pi({a|s}) q_\pi(s,a) $$
</div>
<div>
$$ q_\pi(s,a) = R_s^a + \gamma \sum _ {s'\in S} P_{ss'}^a v_\pi(s') $$
</div>
<p>将上述两个式子互相结合起来，我们可以得到如下的简化（变量）算式（只包含一种价值函数）</p>
<div>
$$ \begin{gathered}v_{\pi}(s)=\sum_{a \in A} \pi(a \mid s)\left(R_{s}^{a}+\gamma \sum_{J \in S} P_{s s^{\prime}}^{a} v_{\pi}\left(s^{\prime}\right)\right) \\q_{\pi}(s, a)=R_{s}^{a}+\gamma \sum_{s^{\prime} \in S} P_{s s^{\prime}}^{a} \sum_{a^{\prime} \in A} \pi\left(a^{\prime} \mid s^{\prime}\right) q_{\pi}\left(s^{\prime}, a^{\prime}\right)\end{gathered} $$
</div>
<h2 id="最优价值函数">最优价值函数</h2>
<p>这一部分看原文，结合相应的例子一起看，后续可能需要看EasyRL中的markov的相关解读来进行深入的理解和计算的分析。</p>
<p>解决一个强化学习的问题意味着要找一个最有的policy（策略），让Argent在和环境交互的过程中获得比其他所有策略都更多的收获，找到这个策略，也就意味着我们解决了这样一个强化学习的问题。</p>
<p>求解最优策略→ 求解最优的价值函数，使得（动作、状态）价值函数获取到最大值的策略就是最优策略。</p>
<p>对于最优策略我们将动作函数定义为：</p>
<div>
$$ \pi_{*}(a \mid s)=\left\{\begin{array}{ll}1 & \text { if } a=\arg \max _{a \in A} q_{*}(s, a) \\0 & \text { else }\end{array}\right. $$
</div>
<p>有：</p>
<div>
$$ v_*(s) = \max_a q_*(s,a)\\q_{*}(s, a)=R_{s}^{a}+\gamma \sum_{s^{\prime} \in S} P_{s s}^{a} v_{*}\left(s^{\prime}\right) $$
</div>
<p>这样我们就可以最终得到：</p>
<div>
$$ \begin{gathered}v_{*}(s)=\max _{a}\left(R_{s}^{a}+\gamma \sum_{g^{\prime} \in S} P_{s s^{\prime}}^{a} v_{*}\left(s^{\prime}\right)\right) \\q_{*}(s, a)=R_{s}^{a}+\gamma \sum_{s^{\prime} \in S} P_{s s^{\prime}}^{a} \max _{a^{\prime}} q_{*}\left(s^{\prime}, a^{\prime}\right)\end{gathered} $$
</div>
<h1 id="chapter3-动态规划dp求解">Chapter3 动态规划（DP）求解</h1>
<p><a href="https://www.cnblogs.com/pinard/p/9463815.html" target="_blank" rel="noopener">强化学习（三）用动态规划（DP）求解</a>
</p>
<ul>
<li>
<p>用动态规划来求解强化学习是自然的</p>
<p><strong>关键的两点</strong>：</p>
<ul>
<li>问题的最优解可以由递归的最优解来得到</li>
<li>子问题状态间的转移</li>
</ul>
<p>从上面推出的贝尔曼方程，这个递推公式实际上就是DP求解的状态转移等式，然后相应的Value什么的也和DP求解过程的需求是一一对应的。</p>
</li>
<li>
<p>关键的方程，通过这种递推公式，我们可以通过上一个迭代周期的状态价值去计算当前迭代周期状态S的状态价值，这也就是动态规划的一个求解的自然过程。</p>
<p>基于贝克曼方程推导出来，推导过程已经在上面了</p>
</li>
</ul>
<div>
$$ v_{\pi}(s)=\sum_{a \in A} \pi(a \mid s)\left(R_{s}^{a}+\gamma \sum_{J \in S} P_{s s^{\prime}}^{a} v_{\pi}\left(s^{\prime}\right)\right) $$
</div>
<hr>
<p>已知条件：状态集S, 动作集A, 模型状态转化概率矩阵P, 即时奖励R，衰减因子γ, 给定策略π</p>
<h2 id="策略评估求解预测问题">策略评估求解预测问题</h2>
<p>策略评估：求解给定策略的状态价值函数的问题，即强化学习的预测问题。</p>
<p>求解思路： 从任何一个状态价值函数开始，按照给定的策略，结合关键的贝尔曼递推期望方程，状态转移，reward，更新状态价值函数，直至最终收敛。</p>
<ul>
<li>
<p>具体而言：</p>
<p>假设第k轮我们已经计算出了所有的状态的状态价值，然后再k+1轮的时候利用k轮的值通过贝尔曼方程来进行更新。</p>
</li>
</ul>
<div>
$$ v_{k+1}(s)=\sum_{a \in A} \pi(a \mid s)\left(R_{s}^{a}+\gamma \sum_{s' \in S} P_{s s^{\prime}}^{a} v_{\pi}\left(s^{\prime}\right)\right) $$
</div>
<p>具体案例上面的网站中去看：（很容易理解）</p>
<h2 id="策略迭代求解控制问题">策略迭代求解控制问题</h2>
<p>控制问题：需要同时求解状态价值函数和策略</p>
<p>策略迭代：从一个初始任意的策略状态，不断地迭代，调整我们的策略，从而得到一个最优的策略。</p>
<p>求解思路：贪婪法</p>
<ul>
<li>
<p>具体而言：</p>
<p>个体在某个状态下选择的行为，是其能够达到后续所有可能的状态中，状态价值最大的那个状态，</p>
</li>
</ul>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911210046.jpg">
    <img alt="https://images2018.cnblogs.com/blog/1042406/201808/1042406-20180812191537706-1156414836.jpg" loading="lazy" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911210046.jpg"class="responsive-image" src="https://picture-bed-001-1310572365.cos.ap-guangzhou.myqcloud.com/imgs/img/20210911210046.jpg" style="display: block; margin: 0 auto;"
      alt="https://images2018.cnblogs.com/blog/1042406/201808/1042406-20180812191537706-1156414836.jpg"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>策略迭代过程的演示：逐步的迭代策略和相应的价值函数，最终使得两者同时收敛</p>
<h2 id="价值迭代求解控制问题">价值迭代求解控制问题</h2>
<p>和上述的策略迭代的问题一样，如果我们使用贪婪的策略去及时调整策略，而不是等到收敛了才调整策略的话，就能很快的减少迭代次数，这样我们状态价值的更新方法也会不太一样，也能更快的收敛</p>
<div>
$$ v_{k+1}(s)=\max_{a \in A} \left(R_{s}^{a}+\gamma \sum_{s' \in S} P_{s s^{\prime}}^{a} v_{\pi}\left(s^{\prime}\right)\right) $$
</div>
<h2 id="异步动态规划算法">异步动态规划算法</h2>
<blockquote>
<p>在前几节我们讲的都是同步动态规划算法，即每轮迭代我会计算出所有的状态价值并保存起来，在下一轮中，我们使用这些保存起来的状态价值来计算新一轮的状态价值。
另一种动态规划求解是异步动态规划算法，在这些算法里，每一次迭代并不对所有状态的价值进行更新，而是依据一定的原则有选择性的更新部分状态的价值，这类算法有自己的一些独特优势，当然有额会有一些额外的代价。
常见的异步动态规划算法有三种：
第一种是原位动态规划 (in-place dynamic programming)， 此时我们不会另外保存一份上一轮计算出的状态价值。而是即时计算即时更新。这样可以减少保存的状态价值的数量，节约内存。代价是收敛速度可能稍慢。
第二种是优先级动态规划 (prioritised sweeping)：该算法对每一个状态进行优先级分级，优先级越高的状态其状态价值优先得到更新。通常使用贝尔曼误差来评估状态的优先级，贝尔曼误差即新状态价值与前次计算得到的状态价值差的绝对值。这样可以加快收敛速度，代价是需要维护一个优先级队列。
第三种是实时动态规划 (real-time dynamic programming)：实时动态规划直接使用个体与环境交互产生的实际经历来更新状态价值，对于那些个体实际经历过的状态进行价值更新。这样个体经常访问过的状态将得到较高频次的价值更新，而与个体关系不密切、个体较少访问到的状态其价值得到更新的机会就较少。收敛速度可能稍慢。</p>
</blockquote>
<p><strong>SUMMARY 动态规划是我们讲到的第一个系统求解强化学习预测和控制问题的方法。它的算法思路比较简单，主要就是利用贝尔曼方程来迭代更新状态价值，用贪婪法之类的方法迭代更新最优策略。</strong></p>
<ul>
<li>
<p>动态规划的缺点：实际上是一种遍历的方式</p>
<p>动态规划算法使用全宽度（full-width）的回溯机制来进行状态价值的更新，也就是说，无论是同步还是异步动态规划，在每一次回溯更新某一个状态的价值时，都要回溯到该状态的所有可能的后续状态，并利用贝尔曼方程更新该状态的价值。这种全宽度的价值更新方式对于状态数较少的强化学习问题还是比较有效的，但是当问题规模很大的时候，动态规划算法将会因贝尔曼维度灾难而无法使用。因此我们还需要寻找其他的针对复杂问题的强化学习问题求解方法。</p>
</li>
</ul>
<h1 id="chapter-4-用蒙特卡罗法求解">Chapter 4 用蒙特卡罗法求解</h1>
<p><a href="https://www.cnblogs.com/pinard/p/9492980.html" target="_blank" rel="noopener">强化学习（四）用蒙特卡罗法（MC）求解</a>
</p>
<p>❓ 由 1. DP方法的全回溯机制（完全遍历）带来的过度的计算复杂度，对于复杂问题的求解困难
2.  很多时候对于状态转化模型P的未知</p>
<ul>
<li>DP中问题预测和控制问题的定义是在P已知的情况下定义的，这种称之为：基于模型的强化学习问题</li>
<li>而一般性预测和控制，也就是在状态转化概率矩阵P未知的情况下求解1. 状态价值函数 和2. 1+最优策略的问题</li>
</ul>
<p>我们需要考虑其他的方法，而不能使用DP方法来求解这样的RL问题——Monto-Calo是一种可行的方法</p>
<p>已知条件：状态集S, 动作集A,  即时奖励R，衰减因子γ，探索率ε</p>
<h2 id="monto-calo-求解">Monto-Calo 求解</h2>
<p>基于采样的思路：蒙特卡罗法通过采样若干经历完整的状态序列(episode)来估计状态的真实价值。</p>
<p>经历完整就是这个序列必须是达到终点的。比如下棋问题分出输赢，驾车问题成功到达终点或者失败。
有了很多组这样经历完整的状态序列，我们就可以来近似的估计状态价值，进而求解预测和控制问题了。</p>
<p>关键公式回顾：</p>
<div>
$$ v_\pi(s) = \mathbb{E}(R_{t+1} + \gamma R_{t+2} + \gamma ^2 R_{t+3} + ... |S_t = s) $$
</div>
<h2 id="mc求解预测问题策略评估">MC求解预测问题（策略评估）</h2>
<p>思路：求解某个s的状态价值：对所有采样到的状态序列中，出现该状态之后的收获再取平均值来近似求解。</p>
<div>
$$ G_t = R_{t+1} + \gamma R_{t+1} + ...+ \gamma ^{T-t+1}R_T \\
V_\pi (s) \approx average(G_t), s.t. S_t = s $$
</div>
<p><strong>一个状态在一个状态序列中多次出现的处理</strong></p>
<p>主要有两种解决方式：</p>
<ol>
<li>First Visit： 只统计第一次出现的来进行均值的计算</li>
<li>Every Visit：每一次出现都加入均值的计算，这种方式更适合样本量少的情况，但是计算量要更大一些。</li>
</ol>
<p><strong>累进更新平均值（Incremental mean）</strong></p>
<p>如果我们将每个状态序列的值都记录下来在最后进行更新的话，会耗费大量的存储空间，所以我们使用累计更新均值的方法来进行不同轮次之间的迭代。</p>
<p>换言之：统计当前的均值和状态遍历到的次数。</p>
<div>
$$ \mu_k = \frac{1}{k} \sum_{j=1}^{k}x_j = \frac{1}{k}(x_k+\sum_{j=1}^{k-1}x_j) = \frac{1}{k}(x_k+(k-1)\mu_{k-1}) = \mu_{k-1} + \frac{1}{k}(x_k-\mu_{k-1}) $$
</div>
<p>然后我们就可以将状态价值公式的更新过程修改成：</p>
<div>
$$ N(S_t) = N(S_t)+1\\
V(S_t) = V(S_t) + \frac{1}{N(S_t)}(G_t-V(S_t)) $$
</div>
<p>这种情况下的存储空间（内存消耗）就是固定的了。</p>
<p>对海量数据做分布式迭代的时候 $N(S_t)$ 计算不确定的情况</p>
<div>
$$ V(S_t) = V(S_t) + \alpha(G_t-V(S_t)) $$
</div>
<p>动作价值函数也是类似的方法。</p>
<h2 id="mc求解控制问题策略迭代">MC求解控制问题（策略迭代）</h2>
<p>和策略迭代的方式也是类似的，也是先做策略评估，然后通过一定的方法（比如贪婪策略）更新策略。</p>
<ul>
<li>和DP相比的不同有如下几点：
<ol>
<li>策略评估的方法不同</li>
<li>MC优化最优动作价值函数而不是状态价值函数</li>
<li>DP一般使用贪婪法，MC使用 $\epsilon$ -贪婪法</li>
</ol>
</li>
</ul>
<p>$\epsilon$ -贪婪法：</p>
<p>一般设置一个较小的值，然后用1- $\epsilon$ 来选择最大行为价值的行为，然后剩下的就随机在m个可行行为中随机选择</p>
<div>
$$ \pi(a \mid s)=\left\{\begin{array}{ll}\epsilon / m+1-\epsilon & \text { if } a^{*}=\arg \max _{a \in A} Q(s, a) \\\epsilon / m & \text { else }\end{array}\right. $$
</div>
<p>为了使得算法收敛； $\epsilon$ 会逐渐减小，并趋于0。</p>
<p>这样会得到一个和动态规划类似的图</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/1042406-20180817164828651-1814136312.jpg">
    <img alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/1042406-20180817164828651-1814136312.jpg" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/1042406-20180817164828651-1814136312.jpg"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/1042406-20180817164828651-1814136312.jpg" style="display: block; margin: 0 auto;"
      alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/1042406-20180817164828651-1814136312.jpg"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><strong>具体的算法流程：</strong></p>
<p>在这里总结下蒙特卡罗法求解强化学习控制问题的算法流程，这里的算法是在线(on-policy)版本的,相对的算法还有离线(off-policy)版本的。在线和离线的区别我们在后续的文章里面会讲。同时这里我们用的是every-visit,即个状态序列中每次出现的相同状态，都会计算对应的收获值。</p>
<p>输入：状态集S, 动作集A, 即时奖励R，衰减因子γ, 探索率ϵ　
输出：最优的动作价值函数q∗和最优策略π∗　</p>
<ol>
<li>
<p>初始化所有的动作价值Q(s,a)=0， 状态次数N(s,a)=0，采样次数k=0，随机初始化一个策略π　</p>
</li>
<li>
<p>k=k+1, 基于策略π进行第k次蒙特卡罗采样，得到一个完整的状态序列:S1,A1,R2,S2,A2,&hellip;St,At,Rt+1,&hellip;RT,ST</p>
</li>
<li>
<p>对于该状态序列里出现的每一状态行为对(St,At)，计算其收获Gt, 更新其计数N(s,a)和行为价值函数Q(s,a)：</p>
</li>
</ol>
<div>
$$ G_t = R_{t+1} + \gamma R_{t+1} + ...+ \gamma ^{T-t+1}R_T \\N(S_t,A_t) = N(S_t,A_t)+1\\
Q(S_t,A_t) = Q(S_t,A_t) + \frac{1}{N(S_t,A_t)}(G_t-Q(S_t,A_t)) $$
</div>
<ol start="4">
<li>基于新计算出的动作价值，更新当前的ϵ−贪婪策略：</li>
</ol>
<div>
$$ \epsilon = \frac{1}{k}\\\pi(a \mid s)=\left\{\begin{array}{ll}\epsilon / m+1-\epsilon & \text { if } a^{*}=\arg \max _{a \in A} Q(s, a) \\\epsilon / m & \text { else }\end{array}\right. $$
</div>
<ol start="5">
<li>如果所有的Q(s,a)收敛，则对应的所有Q(s,a)即为最优的动作价值函数q∗。对应的策略π(a|s)即为最优策略π∗。否则转到第二步。</li>
</ol>
<p><strong>SUMMARY:实际上MC方法就是一个简单的采样渐进求平均的方法，在不断的迭代过程中找到相应的槿近似值。</strong></p>
<h1 id="chapter5-用时序差分法td求解">Chapter5 用时序差分法（TD）求解</h1>
<p><a href="https://www.cnblogs.com/pinard/p/9529828.html" target="_blank" rel="noopener">强化学习（五）用时序差分法（TD）求解</a>
</p>
<p>蒙特卡洛法虽然灵活，不需要环境转化概率模型，但是也有限制：所有的采样序列都需要是完整的状态序列，如果没有完整的状态序列，就不能使用Monto-Calo了。</p>
<p>在不完整的状态序列的情况下，可以使用时序差分算法（Temporal-Difference，TD），这也是一种不基于模型的算法（也就是没有环境转移的情况下）</p>
<p>关键公式回顾：</p>
<div>
$$ 蒙特卡洛：G_t = R_{t+1} + \gamma R_{t+1} + ...+ \gamma ^{T-t+1}R_T \\
<p>贝尔曼（TD）：v_{\pi}(s) = =\mathbb{E}{\pi}\left(R_{t+1}+\gamma v_{\pi}\left(S_{t+1}\right) \mid S_{t}=s\right)
$$</p>
</div>
<p>由于如果使用G的公式的话，我们需要有T时刻的R来进行计算分析， 为了简化这个过程，我们使用贝尔曼的递推式来进行时序差分的分析（实际上是同个等式）</p>
<p>也就是：</p>
<p>使用 $R_{t+1} + \gamma v(S_{t+1})$ （也称为TD目标值） 来代替收获 $G_t$ ，同时令 $R_{t+1} + \gamma v(S_{t+1}) - V(S_t)$ 称为TD误差，用TD目标值来代替收获G的过程称为引导。这样的话我们只需要两个连续的状态和对应的奖励，就可以尝试求解强化学习的问题了。</p>
<h2 id="td预测问题求解">TD预测问题求解</h2>
<p>预测问题的求解思路大体上是类似的，但是和MC有两个主要的不同点:</p>
<p><strong>一个是 $G_t$ 收获的表达式不同</strong></p>
<div>
$$ G(t) = R_{t+1} + \gamma v(S_{t+1}) $$
</div>
<p><strong>二是迭代的系数稍微有些不同，因为没有完整的序列，所以就没有对应的次数N，所以就用一个[0,1]的系数来代替</strong></p>
<div>
$$ V\left(S_{t}\right)=V\left(S_{t}\right)+\alpha\left(G_{t}-V\left(S_{t}\right)\right) $$
</div>
<p>具体的例子请参考相应的链接，这里写的特别的清楚！GO TO URL</p>
<p><strong>从例子中我们可以看到MC和TD主要的几点区别：</strong></p>
<ol>
<li>时序差分法在知道结果之前就可以学习，也可以在没有结果时学习，还可以在持续进行的环境中学习，而蒙特卡罗法则要等到最后结果才能学习，时序差分法可以更快速灵活的更新状态的价值估计，这在某些情况下有着非常重要的实际意义。‘</li>
<li>时序差分法在更新状态价值时使用的是TD 目标值，即基于即时奖励和下一状态的预估价值来替代当前状态在状态序列结束时可能得到的收获，是当前状态价值的有偏估计，而蒙特卡罗法则使用实际的收获来更新状态价值，是某一策略下状态价值的无偏估计，这一点蒙特卡罗法占优。</li>
<li>虽然时序差分法得到的价值是有偏估计，但是其方差却比蒙特卡罗法得到的方差要低，且对初始值敏感，通常比蒙特卡罗法更加高效。</li>
</ol>
<p>所以后续的主流的强化学习方法都是基于时序差分的，后面的文章也会主要基于时序差分来拓展讨论。</p>
<p>SUMMARY: 实际上TD和对应的DP最大的区别就在于G(t)的计算，从这里可以体现出DP主要依靠的是当前值再所有出现的序列中的状态值的平均，而TD可以依靠其他变量进行递推的这点优势。</p>
<h2 id="n步时序差分">n步时序差分</h2>
<p>前面我们的递推式只考虑了一步差分来进行近似，但是实际上我们可以将差分式子变形，变成二次差分项</p>
<div>
$$ G_t^{(2)} = R_{t+1} + \gamma R_{t+2} + \gamma^2 V(S_{t+1}) $$
</div>
<p>也可以一次类推到n步的差分项，当n趋于无穷的时候，实际上就等价于MC方法了。</p>
<h2 id="td-lambda-">TD（ $\lambda$ ）</h2>
<p>n步时序差分选择多少步数是一个超参数调优的过程，为了再不增加计算复杂度的时候综合考虑所有步数的预测，引入一个新的[0,1]的参数λ，定义λ-收获是n从1到∞所有步的收获*权重的和，每一步的权重带有一定的比例，如下：</p>
<div>
$$ G_t^\lambda = (1-\lambda)\sum_{n=1}^\infin \lambda^{n-1}G_t^{(n)} $$
</div>
<p>因此我们就能得到TD（λ）的迭代公式：Q也是类似的，就不重新写一次了</p>
<div>
$$ V(S_t) = V(S_t)+\alpha(G_t^\lambda - V(S_t)) $$
</div>
<p>权重衰减的原因如下，随着n增大，权重成集合级数衰减，在T时刻把所有剩余的权重给最终状态，这样可以使得权重嘉禾为1，里当前越远权重越小。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/1042406-20180824163740251-607605293.jpg">
    <img alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/1042406-20180824163740251-607605293.jpg" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/1042406-20180824163740251-607605293.jpg"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/1042406-20180824163740251-607605293.jpg" style="display: block; margin: 0 auto;"
      alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/1042406-20180824163740251-607605293.jpg"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>从前向来看TD(λ)， 一个状态的价值V(St)由Gt得到，而Gt又间接由所有后续状态价值计算得到，因此可以认为更新一个状态的价值需要知道所有后续状态的价值。也就是说，必须要经历完整的状态序列获得包括终止状态的每一个状态的即时奖励才能更新当前状态的价值。这和蒙特卡罗法的要求一样，因此TD(λ)有着和蒙特卡罗法一样的劣势。当λ=0 时,就是第二节讲到的普通的时序差分法，当λ=1 时,就是蒙特卡罗法。</p>
<p>从反向来看TD(λ)，它可以分析我们状态对后续状态的影响。比如老鼠在依次连续接受了3 次响铃和1 次亮灯信号后遭到了电击，那么在分析遭电击的原因时，到底是响铃的因素较重要还是亮灯的因素更重要呢？如果把老鼠遭到电击的原因认为是之前接受了较多次数的响铃，则称这种归因为频率启发(frequency heuristic) 式；而把电击归因于最近少数几次状态的影响，则称为就近启发(recency heuristic) 式。</p>
<p>如果给每一个状态引入一个数值：效用(eligibility, E) 来表示该状态对后续状态的影响，就可以同时利用到上述两个启发。而所有状态的效用值总称为效用迹(eligibility traces,ES)。定义为：</p>
<div>
$$ \begin{gathered}E_{0}(s)=0 \\E_{t}(s)=\gamma \lambda E_{t-1}(s)+1\left(S_{t}=s\right)=\left\{\begin{array}{ll}0 & t<k \\(\gamma \lambda)^{t-k} & t \geq k\end{array}, \text { s.t. } \lambda, \gamma \in[0,1], s \text { is visited once at time } k\right.\end{gathered} $$
</div>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/20200218133233516.png">
    <img alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/20200218133233516.png" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/20200218133233516.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/20200218133233516.png" style="display: block; margin: 0 auto;"
      alt="https://raw.githubusercontent.com/AikenH/md-image/master/img/20200218133233516.png"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>可以看到一个状态要是重复出现的话都会让效用迹增加，不然的话就会一直衰减。</p>
<p>这样最终TD（λ）的股票公式就可以更新为：（反向公式这应该是）</p>
<div>
$$ \begin{gathered}\delta_{t}=R_{t+1}+\gamma v\left(S_{t+1}\right)-V\left(S_{t}\right) \\V\left(S_{t}\right)=V\left(S_{t}\right)+\alpha \delta_{t} E_{t}(s)\end{gathered} $$
</div>
<p>然后可以看出这两个公式是存在一致性的。</p>
<h2 id="td控制问题求解">TD控制问题求解</h2>
<p>实际上还是使用同样的ε-贪婪进行策略和价值迭代。</p>
<p>在线控制最常见的是SARSA算法</p>
<p>离线控制比在线控制多了一个策略，用贪婪发来更新价值函数，用一样的来进行动作选择，最常见的是Q-Learning算法。</p>
]]></content:encoded>
    </item>
    <item>
      <title>经典深度学习与机器学习算法</title>
      <link>https://aikenh.cn/posts/intview_%E9%9D%A2%E8%AF%95%E8%A1%A5%E5%85%85/</link>
      <pubDate>Fri, 23 Apr 2021 01:43:43 +0000</pubDate>
      <guid>https://aikenh.cn/posts/intview_%E9%9D%A2%E8%AF%95%E8%A1%A5%E5%85%85/</guid>
      <description>additional information for interview</description>
      <content:encoded><![CDATA[<head>
    
    <script src="https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/crypto-js/3.1.9-1/crypto-js.js"></script>
</head>





<div class="hugo-encryptor-container">
  <div class="hugo-encryptor-prompt">
    
      <p>文章的部分内容被密码保护：</p>
    
  </div>
  <div class="hugo-encryptor-form">
    <input
      class="hugo-encryptor-input"
      placeholder='请输入密码'
    />
    <input
      class="hugo-encryptor-button"
      type="button"
      value='CLICK'
      onclick="_click_handler(this)"
    />
  </div>
  <div
    class="hugo-encryptor-cipher-text"
    data-password="aikenhong_blog"
    style="display: none;"
  >
    <span style="display: none;">--- DON'T MODIFY THIS LINE ---</span>
    <p><a href="https://blog.csdn.net/cppjava_/article/details/68921869" target="_blank" rel="noopener">LINK1</a>
</p>
<h2 id="深度学习部分">深度学习部分</h2>
<h3 id="densenet">DenseNet</h3>
<p>任意的两层之间都存在直接的链接，每一层的输入都是前面的所有层的输出的并集，而该层学习的特征图也会是后面所有层的输入，DenseBlock中需要Feature_map保持一致；</p>
<p>Block与Block之间的降采样则使用transition layer，使用BN，1*1的 conv，Pooling来降维</p>
<p>优缺点：</p>
<ol>
<li>省参数，省计算</li>
<li>抗过拟合，泛化能力强</li>
<li>需要保存Feature占显存</li>
</ol>
<h3 id="efficientnet">EfficientNet</h3>
<p>针对卷积神经网络的模型拓展，可以通过：1</p>
<ol>
<li>增加网络规模可以、 增加<strong>模型宽度</strong>，增加<strong>模型深度</strong>，增加<strong>输入图像的分辨率</strong>，但是如何去人工调整这个比例和参数，比较麻烦，</li>
<li>实验发现ConvNet缩放过程中平衡网络宽度、深度、和分辨率的维度是很重要的</li>
<li>EfficientNet就是对这些的合理组合，复合型的模型扩展技术集合神经结构搜索技术获得</li>
</ol>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-fcbff6e21eb9e7f9cce94c3bd935b84a_720w2.jpg">
    <img alt="img" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-fcbff6e21eb9e7f9cce94c3bd935b84a_720w2.jpg"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-fcbff6e21eb9e7f9cce94c3bd935b84a_720w2.jpg" style="display: block; margin: 0 auto;"
      alt="img"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><strong>关键技术</strong>复合扩张技术</p>
<p>所以本文提出了<strong>复合扩张方法</strong>，这也是文章核心的地方，</p>
<div>
$$ \alpha,\beta,\gamma $$
</div>
 是我们需要求解的一组参数，如下图公式，带约束的最优参数求解。 
<div>
$$ \alpha,\beta,\gamma $$
</div>
 分别衡量着depth, width和 resolution的比重，其中 
<div>
$$ \beta,\gamma $$
</div>
 在约束上会有平方，是因为如果增加宽度或分辨率两倍，其计算量是增加四倍，但是增加深度两倍，其计算量只会增加两倍。
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-d158f21d6bae78f05fbcf40fd81255d3_720w.jpg">
    <img alt="img" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-d158f21d6bae78f05fbcf40fd81255d3_720w.jpg"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-d158f21d6bae78f05fbcf40fd81255d3_720w.jpg" style="display: block; margin: 0 auto;"
      alt="img"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ol>
<li>固定公式中的φ=1，然后通过网格搜索（grid search）得出最优的α、β、γ，得出最基本的模型EfficientNet-B0.</li>
<li>固定α、β、γ的值，使用不同的φ，得到EfficientNet-B1, &hellip;, EfficientNet-B7</li>
</ol>
<p>φ的大小对应着消耗资源的大小，相当于：</p>
<ol>
<li>当φ=1时，得出了一个最小的最优基础模型；</li>
<li>增大φ时，相当于对基模型三个维度同时扩展，模型变大，性能也会提升，资源消耗也变大。</li>
</ol>
<h3 id="bottleneck">bottleneck</h3>
<p>Bottleneck layer又称之为瓶颈层，使用的是1*1的卷积神经网络。之所以称之为瓶颈层，是因为长得比较像一个瓶颈。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-a78418d8f2dc346cd284a22f20e66af7_720w.jpg">
    <img alt="img" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-a78418d8f2dc346cd284a22f20e66af7_720w.jpg"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-a78418d8f2dc346cd284a22f20e66af7_720w.jpg" style="display: block; margin: 0 auto;"
      alt="img"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
中间比较细，像一个瓶颈</p>
<p>如上图所示，经过 $1<em>1 conv$ ，中间那个看起来比较细。像一个瓶颈一样。使用 $1</em>1$ 网络的一大好处就是可以大幅减少计算量。深度可分离卷积中，也有这样的设计考虑。如果想具体了解如何大幅减少计算量的话，可以参考参考资料[2]</p>
<h3 id="xavier参数初始化方法">Xavier参数初始化方法</h3>
<p>已经写在笔记上了，但是还要补充的，或者说是理清楚的是怎么推导的或者为什么这么干的，还有其他的初始化方法之间的区别什么的</p>
<h3 id="模型压缩">模型压缩</h3>
<p>为了研究小而快的机器学习模型：1. 对复杂模型进行压缩 2. 直接设计小模型得到训练</p>
<h4 id="轻量网络mobilenet">轻量网络：MobileNet</h4>
<p>主要的网络架构：是使用<strong>depthwise separable convolution</strong>也就是xception中提到的这种，双分离的卷积</p>
<p>然后使用：<strong>ReLU6</strong>激活函数（限制最大输出为6）</p>
<p>过程中<strong>不使用pooling直接使用stride=2</strong>进行下采样</p>
<p>基本的组件如图所示： 最后用avg pooling从 $7<em>7</em>1024 $ 到 $1<em>1</em>1024$</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/20180615124806760">
    <img alt="img" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/20180615124806760"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/20180615124806760" style="display: block; margin: 0 auto;"
      alt="img"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>对其进行瘦身：</p>
<ul>
<li>按比例缩放特征图的大小</li>
<li>按比例缩放通道数</li>
</ul>
<p>核心的计算量实际上在 $1*1 conv$ 这个全通道密集卷积的操作上</p>
<p><strong>V2：</strong></p>
<ul>
<li>
<p>引入了shortcut（残差结构）</p>
</li>
<li>
<p>在进行depthwise之前先用 $1*1$ 扩张feature_map的通道数</p>
<blockquote>
<p>是为了提升效果，参数量比1还是稍微增加了，</p>
<p>这里的1*1和resnet中的是完全相反的：</p>
<p>残差模块：1<em>1降维 3</em>3卷积 1<em>1升维
反残差模块：1</em>1升维，3<em>3卷积，1</em>1降维</p>
<p>原因：因为depthwise卷积不能改变通道数，因此特征提取受限于输入的通道数，所以将通道数先提升上去。文中的扩展因子为6。</p>
</blockquote>
</li>
<li>
<p>pointwise之后的relu改成了Linear激活函数，防止relu破坏特征</p>
<blockquote>
<p>原因：relu造成的低维度数据塌陷<br></p>
<p><a href="https://www.sohu.com/a/307566264_100024677" target="_blank" rel="noopener">https://www.sohu.com/a/307566264_100024677</a>
</p>
<p>就是当低维信息映射到高维，经过ReLU后再映射回低维时，若映射到的维度相对较高，则信息变换回去的损失较小；若映射到的维度相对较低，则信息变换回去后损失很大。因此，认为对低维度做ReLU运算，很容易造成信息的丢失。而在高维度进行ReLU运算的话，信息的丢失则会很少。<br>
因为relu函数小于0时候，值为0，是有信息损耗的，而线性激活函数没有信息损耗</p>
</blockquote>
</li>
</ul>
<h4 id="轻量网络shufflenet">轻量网络：Shufflenet</h4>
<p><a href="https://www.zhihu.com/search?q=shufflenet&amp;utm_content=search_suggestion&amp;type=content" target="_blank" rel="noopener">V1 带Pytorch</a>
</p>
<p>ShuffleNet的核心是采用了两种操作：<strong>pointwise group convolution</strong>和<strong>channel shuffle</strong>，这在保持精度的同时大大降低了模型的计算量。</p>
<p>缓解 $1*1 conv$ 的计算量，也使用channel sparse connection，但是这种group convolution 也有弊端：特征图之间不通信，所以我们就channel shuffle（均匀打乱）</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-f8ddc33fb1f578bf7f51a4b6e5407426_r.jpg">
    <img alt="preview" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-f8ddc33fb1f578bf7f51a4b6e5407426_r.jpg"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-f8ddc33fb1f578bf7f51a4b6e5407426_r.jpg" style="display: block; margin: 0 auto;"
      alt="preview"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>图3.(a)是一个普通的带有残差结构的深度可分离卷积，例如，<a href="https://zhuanlan.zhihu.com/p/50045821" target="_blank" rel="noopener">MobileNet</a>
[5], <a href="https://zhuanlan.zhihu.com/p/50897945" target="_blank" rel="noopener">Xception</a>
[6]。ShuffleNet v1的结构如图3.(b)，3.(c)。其中3.(b)不需要降采样，3.(c)是需要降采样的情况。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-fdf77861cd24ab65be0c81934e7e3af2_r.jpg">
    <img alt="preview" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-fdf77861cd24ab65be0c81934e7e3af2_r.jpg"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-fdf77861cd24ab65be0c81934e7e3af2_r.jpg" style="display: block; margin: 0 auto;"
      alt="preview"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p><strong>V2:</strong></p>
<ol>
<li>G1). 使用输入通道和输出通道相同的卷积操作；</li>
<li>G2). 谨慎使用分组卷积；</li>
<li>G3). 减少网络分支数；</li>
<li>G4). 减少element-wise操作。</li>
</ol>
<p>通道分割在每个单元开始前将通道的输入分成两个，不再使用group卷积，然后concat两个channel并channel shuffle</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-eee995e9167bde760a6aab6c4b30c794_720w.jpg">
    <img alt="img" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-eee995e9167bde760a6aab6c4b30c794_720w.jpg"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-eee995e9167bde760a6aab6c4b30c794_720w.jpg" style="display: block; margin: 0 auto;"
      alt="img"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h4 id="轻量网络squeezenet">轻量网络：squeezeNET</h4>
<p>利用Fire module 来实现了：<a href="https://zhuanlan.zhihu.com/p/49465950" target="_blank" rel="noopener">Link</a>
</p>
<h4 id="knowledge-distiall">Knowledge Distiall</h4>
<p>实际上很简单，就是用小模型逼近大模型的输出，用大模型来做小模型的监督，也就是让小模型尽量去适应大模型的输出分布（原本应该只是一个类别标签），这其实已经偏向于一个无监督的驯良过程了，或者说是自监督。</p>
<ul>
<li>训练大模型</li>
<li>计算大模型的soft output</li>
<li>训练小模型，在类别的监督信息以外再加上soft target的loss，用lambda来调节传中</li>
<li>使用小模型进行预测。</li>
</ul>
<h3 id="超参数搜索的方法">超参数搜索的方法</h3>
<p>网格搜索，随机搜索，贝叶斯优化方法（这种方法实际上还不是太清楚，后面可能还需要看看），AutoML</p>
<h3 id="激活函数的稀疏性">激活函数的稀疏性</h3>
<ol>
<li>适应性强，针对不同的情况有不同的激活单元</li>
<li>简洁的模型，计算更快</li>
<li>更好的预测能力和更不容易过拟合</li>
<li>更可分</li>
</ol>
<h3 id="梯度消失与爆炸">梯度消失与爆炸</h3>
<p>消失：sigmoid ，tanh，</p>
<p>误差的反向传播造作，我们可以看出这种连乘的形式涉及到了很多的参数和导数，这种时候无论是放大还是缩小的效应都很容易累加起来产生梯度的消失或者膨胀，</p>
<blockquote>
<p>当对当前层的w进行求导的时候，我们需要先对上一层的x求导，就会得到wt+1 与梯度连乘这样的式子，这也是导致梯度爆炸的原因</p>
<p>sigmoid的最大输出只有1/4所以sigmoid中梯度消失实际上是更常见的时候</p>
</blockquote>
<p>再RNN中BPTT这种反向传播的时候也是类似的思路，但是它是以一个n维矩阵的方式向后传播的，这样当雅可比矩阵的特征值小于1的时候，这样的梯度传播会呈现指数级的变化，要么梯度消失要么梯度爆炸</p>
<p>ResNet 缓解深层网络中梯度消失的问题，实际并不是真正的解决这样的问题，只是给出了一个传播的shortcut，所以掩盖了梯度消失的情况出现，实际上ResNet解决更多的是模型退化的问题，也就是</p>
<p>梯度爆炸也可以使用梯度裁剪的方法进行解决：当梯度的范数大于阈值的时候，我们对梯度进行等比的搜索，</p>
<h3 id="损失函数的反向推导">损失函数的反向推导</h3>
<p>常见的几个损失函数和误差之间的关系（推一下grad的公式）</p>
<ul>
<li>Softmax</li>
<li>CE</li>
</ul>
<h3 id="过拟合欠拟合的判断和处理方式">过拟合欠拟合的判断和处理方式</h3>
<p><strong>过拟合</strong>的训练方法：</p>
<ul>
<li>
<p>获取更多数据</p>
</li>
<li>
<p>降低模型的复杂度</p>
</li>
<li>
<p>正则化方法：实际上这就是权重衰减的方法这里药剂的L1（直接减少有效参数的数量），L2正则化结构风险（减少权值过大带来的过拟合的风险）的那些具体定义；dropout等等。</p>
<blockquote>
<p>drop可以理解成bagging的办法的继承实现</p>
</blockquote>
</li>
<li>
<p>集成学习方法，通过多个模型的集成来降低单一模型的过拟合风险</p>
</li>
<li>
<p>early-stop</p>
</li>
</ul>
<p><strong>DROPOUT rescale</strong></p>
<p>使用 pretraining 方法也可以帮助 dropout 训练参数，在使用 dropout 时，要将所有参数都乘以 $ 1/p$</p>
<ul>
<li>开始时随机删除，一半P的神经元</li>
<li>在剩下的一般中更新，</li>
<li>recycle，然后，最后学出来的参数的存在概率只有（1-P)所以要*概率。</li>
</ul>
<p><strong>欠拟合降低的方法</strong>：</p>
<ul>
<li>添加新特征：特征与标签之间的相关性太差，我们可能需要挖掘新的特征；</li>
<li>增加模型的复杂度：简单模型的学习能力可能太差了，比如在线性模型中添加高次项，增加网络的深度或者神经元个数</li>
<li>减少正则化参数</li>
</ul>
<h3 id="有监督学习中涉及到的损失函数">有监督学习中涉及到的损失函数</h3>
<p><a href="https://zhuanlan.zhihu.com/p/77686118?utm_source=qq" target="_blank" rel="noopener">LINKLINE</a>
</p>
<ul>
<li>0，1损失函数： $max{0,1-fy}$ ,标签，二分类问题</li>
<li>hinge损失（0，1的进化）：max{0,1-fy}</li>
</ul>
<h3 id="卷积">卷积</h3>
<p>卷积的矩阵加速：https://www.mobibrw.com/2019/17787</p>
<p>转置卷积：<a href="https://blog.csdn.net/lanadeus/article/details/82534425" target="_blank" rel="noopener">LInk1</a>
 ；<a href="https://blog.csdn.net/tsyccnh/article/details/87357447" target="_blank" rel="noopener">LInk2</a>
</p>
<p>转置卷积上采样带来的棋盘效应：https://www.cnblogs.com/hellcat/p/9707204.html</p>
<p>空洞卷积也会带来棋盘效应，也就是采样不均匀，有些点被重复采样，有些点没有被采样到，这样就会像棋盘一样，两种颜色分离的这种情况。</p>
<p>上采样 下采样：</p>
<p>SVD：https://www.cnblogs.com/endlesscoding/p/10033527.html</p>
<h3 id="正则化的具体函数和内在含义">正则化的具体函数和内在含义</h3>
<p>KEYPOINT：https://www.cnblogs.com/alexanderkun/p/6922428.html</p>
<p>实际上我们可以发现这也是一个权重衰减的操作，如果从导数去分析的话，或者我们数形结合，我们会发现这样的w和我们的函数曲线的交点实际上是偏向</p>
<p>Regularization：在目标函数中添加惩罚项，对复杂度高的模型进行惩罚，于是考虑从W的向量出发，</p>
<ul>
<li>
<p>0范数：非零元素的个数，在机器学习中是个NP完全问题，很难求</p>
</li>
<li>
<p>1范数：绝对值之和</p>
</li>
<li>
<p>2范数，通常意义上的模，实际上从分布上来看</p>
<blockquote>
<p><strong>L2范数是指向量各元素的平方和然后求平方根。我们让L2范数的正则项||W||2最小，可以使得W的每个元素都很小，都接近于0，但与L1范数不同，它不会让它等于0，而是接近于0，这里是有很大的区别的哦；所以大家比起1范数，更钟爱2范数。</strong></p>
</blockquote>
</li>
</ul>
<h3 id="normalization">Normalization</h3>
<p><a href="https://zhuanlan.zhihu.com/p/33173246" target="_blank" rel="noopener">重要参考资料</a>
 ；<a href="https://www.zhihu.com/question/68730628/answer/277339783" target="_blank" rel="noopener">参考资料2向东的回答</a>
</p>
<p>权重伸缩不变性，可以有效的提高反向传播的效率，也有参数正则化的效果；</p>
<p>数据伸缩不变性；减少梯度弥散，简化对学习率的选择</p>
<h4 id="covariate-shift">covariate shift</h4>
<p>协方差偏移，实际上是训练集和测试集中，变量的分布的不同带来的问题，这样就会导致模型的效果收到影响，也会印象网络的迭代速度，通过BN就可以将每个mini-batch的数据都拉回到标准正态分布，把带有偏差的数据拉回标准分布，拉回模型擅长的领域中，使得梯度变大，避免梯度小时的问题出现，也能加快收敛的速度。</p>
<p><a href="https://blog.csdn.net/mao_xiao_feng/article/details/54317852" target="_blank" rel="noopener">帮助理解covariate shift</a>
，更确切的来说，实际上是source domain和Target domain的数据分布不一致，他们的条件概率相同，但是边缘概率不同：</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210313144706811.png">
    <img alt="image-20210313144706811" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210313144706811.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210313144706811.png" style="display: block; margin: 0 auto;"
      alt="image-20210313144706811"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<ul>
<li>
<p>这样会导致不再是独立同分布：</p>
</li>
<li>
<p>需要不断适应输入的分布，降低学习速度</p>
</li>
<li>
<p>下端的变化可能趋向于变大或者变小，容易使得上层落入饱和区，学习过早的停止</p>
</li>
<li>
<p>会相互影响。</p>
</li>
</ul>
<h4 id="bninlnwn">BN，IN，LN，WN</h4>
<p>Normalization的基本框架就是 $h=f(g·\frac{x-\mu}{\sigma} + b)$</p>
<p>再次进行平移和缩放是为了模型的表达能力不因规范化而下降；这两个缩放因子是可以学习的，用来对底层的学习结果有所价值，这也会将数据变换到基本在非饱和区中（线性区），然后通过再次的缩放和偏移，提供了非线性。</p>
<p><strong>BNnormalization纵向</strong></p>
<p>是对同一个batch的所有图的逐channel进行的</p>
<img src="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-ee8f2d5e3a002fd0ecf47cc094d935a5_720w.jpg" alt="img" style="zoom:50%;" />
<p>使用mini-batch来计算相关的均值和方差，element-wised；但是BN是独立的对每个维度（channel）进行统计的，这样的话，如果原始分布差距很大的话，会导致不同的数据训练，这样可能会增加模型的训练难度。</p>
<p>适用场景：每个mini-batch比较大，数据分布比较接近，所以我们需要进行充分的shuffle，不然效果会差很多。再运行中需要统计一阶和二阶统计量，所以不适用动态的网络架构和RNN，；相应的改造就不说了</p>
<p>适用于判别模型中，</p>
<p><strong>Instance Normalization</strong></p>
<img src="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-7092a1ff8c48cbd1a79044cbb3346856_720w.jpg" alt="img" style="zoom: 50%;" />
<p>是对单张图片的单个通道单独进行的Normalization，适用于生成模型中，比如风格迁移，主要依赖的是单张图片的实例，所以不适宜对整个batch进行归一化，这样可以加速模型收敛和保证实例之间的独立性</p>
<p><strong>Group Normalization</strong></p>
<p>实际上就是一个normalization的变体：</p>
<img src="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-4d4320b6e285c108f8e11bea650a3d32_720w.jpg" alt="img" style="zoom:50%;" />
<p><strong>Layer Normalization 横向</strong></p>
<p>是指对同一张图片的同一层的所有通道进行的normalization，所以和公式不一样的就是不需要求M的均值了，是对同一张图片的所有channel进行的</p>
<img src="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-f8df6b9a4c8b4d39a3521f3738a9dff4_r.jpg" alt="preview" style="zoom:50%;" />
<p><strong>Wegiht Normalization参数规范化</strong></p>
<p><strong>CosineNormalization</strong></p>
<h3 id="解释一下attention">解释一下attention</h3>
<blockquote>
<p>在某种程度上，注意力是由我么如何关注视觉图像的不同区域或者我们如何关联同一个句子中的不同单词所启发的：针对于问题的不同，我们会对图像的某些具体的区域重视（某些区域在视觉中呈现高分辨率，而另一些则是低分辨率的情况），或者句子中的某些词重视的情况。</p>
</blockquote>
<p>比如我们看到eating就对food有更高的attention，与此同时color的权重就会比较低。</p>
<p><strong>因为传统的RNN架构，固定的context vector可能会导致序列信息的缺失，可能无法记住长句子和时序对齐的信息，所以诞生了attention.</strong></p>
<p>content vector和 attention weight加权，然后和上一个时刻的target和y，生成现在的y。</p>
<p>self-attention：https://zhuanlan.zhihu.com/p/47282410；</p>
<p>内部注意力，也就是内部的自我关联的获取，QKV的关系</p>
<h4 id="transformer-的基本架构">Transformer 的基本架构</h4>
<p>Transformer 的 Multi-Head 实际上就是有不同的QKV表示，然后我们将其表示起来。</p>
<p>mask屏蔽未来的信息</p>
<h3 id="pooling的反向传播">Pooling的反向传播：</h3>
<p>Pooling层的主要作用</p>
<p>1、特征不变性，使模型更加关注是否存在某些特征而不是特征具体的位置，对于一些旋转和平移具有不变性        <br>
2、特征降维，使模型可以抽取更广泛围的特征，减小了下一层输入大小，进而减小计算量和参数个数</p>
<p>3、在一定程度防止过拟合，更方便优化</p>
<p>4、扩大感受野</p>
<p>avg pooling：均分后回传</p>
<p>MaxPooling：只传给最大的一项，其他项的反向传播值为0</p>
<h3 id="anchor-based和-anchor-free的理解和辨析">Anchor-based和 Anchor-free的理解和辨析</h3>
<p>实际上就是把五百问的内容再巩固一下，然后整理过来，这里还有两个比较相关的链接，到时候还不清楚就可以看下。</p>
<p><a href="https://www.zhihu.com/question/356551927/answer/926659692" target="_blank" rel="noopener">https://www.zhihu.com/question/356551927/answer/926659692</a>
</p>
<p><a href="https://zhuanlan.zhihu.com/p/62372897" target="_blank" rel="noopener">https://zhuanlan.zhihu.com/p/62372897</a>
</p>
<p>Anchor-based方法：在选练之前在训练集熵使用K-Means等聚类方法聚类出一组矩形框，代表主要的长宽，然后在推理时用这些Anchor滑动提取proposal之后在对这些Anchor进行回归和分类，比如扩张和中心点预测</p>
<p>Anchor-free:就是没有预先定义这样的BoundingBox，直接通过网络来预测相应的边框，比如左上角右下角，中心点这样的预测；中心点+长宽</p>
<h2 id="机器学习部分">机器学习部分</h2>
<h3 id="回归任务为什么难以训练">回归任务为什么难以训练</h3>
<ul>
<li>目标更难，需要适应所有的点</li>
<li>损失函数的角度，MSE之类的，下降与Value相关，对Outline敏感</li>
</ul>
<h3 id="selective-search-hog-sift">Selective Search HOG SIFT</h3>
<p>HOG: 手机知乎</p>
<p>Selective Search：https://zhuanlan.zhihu.com/p/27467369</p>
<p>SIFT：<a href="https://zhuanlan.zhihu.com/p/70385018" target="_blank" rel="noopener">概览</a>
 ； <a href="https://zhuanlan.zhihu.com/p/261697473" target="_blank" rel="noopener">开贴细说</a>
</p>
<h3 id="lr怎么处理低维线性不可分问题">LR怎么处理低维线性不可分问题</h3>
<p>特征工程或者使用多项式核和高斯核，将样本映射到可分的空间去进行逻辑回归；</p>
<p><strong>线性回归和逻辑回归的异同点</strong></p>
<p>实际上都是一个函数映射的问题，就是离散化和连续化的区别而已，还有其中的损失函数的设计等等</p>
<p>线性回归和逻辑回归实际上都是线性模型，但是最终一个映射到连续域做拟合，另一个映射到离散域做分类，最主要的区别就在于目的，输出值域，以及损失函数的设计上。</p>
<p>本质上都是一个一个线性映射函数的选择。</p>
<h4 id="lr对连续值特征是怎么处理的">LR对连续值特征是怎么处理的</h4>
<p>离散化的作用和优势：https://notes.001.io/lian-xu-te-zheng-li-san-hua/</p>
<p>LR本质上属于广义线性模型，通过进行值域的划分，相当于引入了非线性，从而提升了模型的表达能力；</p>
<p>进行离散化后对异常值不敏感，能对轻微的扰动有一定的鲁棒性，但是这还是比较考验特征划分技术的</p>
<p>可以对离散的特征值进行组合，进一步引入非线性</p>
<p>相当于简化了逻辑回归的模型，引入模型复杂度的正则化，这样能够减少过拟合的风险。</p>
<h4 id="lr为什么要归一化">LR为什么要归一化</h4>
<p>LR的求解过程不就是是梯度下降的方式，那么就是归一化的作用了没什么好说的</p>
<h3 id="集成学习方法">集成学习方法</h3>
<h4 id="boosting">Boosting</h4>
<p>基学习器，做错的样本受到更多的关注，然后调整后的样本分布进行下一个基学习器的训练（AdaBoost）</p>
<p>对特定的数据分布进行学习，实际上就像是re-weighting的这样的操作；如果不能使用这种方法的模型我们就使用re-sampling的操作来处理。</p>
<ul>
<li>过程中如果不满足比随机猜测好，这种模型就直接停止</li>
<li>可以看出这种方法主要关注降低偏差，可以对弱学习器构建出很强的集成</li>
</ul>
<h4 id="bagging与随机森林">Bagging与随机森林</h4>
<p>又放回的随机抽取样本构建包含m个的数据集，采样出T个这样的数据集，然后对这些基学习器进行结合，（简单投票做分类，简单平均做回归）</p>
<p>随机森林是在以决策树为基础构建的基学习器，在bagging的基础上，引入了随机的属性选择（原本是选择最优的），也就是先选择一个随机的子集，然后在子集中选择最优的用来划分。</p>
<h4 id="gbdt和xgboost">GBDT和XGBoost</h4>
<p>GBDT实际上就是BOOSTing的一种方法</p>
<p>都是通过损失函数相对于模型的负梯度方向来对当前的模型进行更新，但是在<strong>梯度下降</strong>里，我们的模型是通过参数表示的，而在<strong>梯度提升</strong>，是在函数空间中直接表示的。</p>
<p>通俗一点的说的话，实际上就是梯度下降是在更新梯度来进行梯度下降，梯度提升通过累加弱学习器来梯度下降。</p>
<p>关键：<strong>实际上在梯度提升中，梯度最终会被计算为（当作）残差</strong>，也就是用损失函数的负梯度去模拟残差</p>
<p><a href="https://www.cnblogs.com/jiangxinyang/p/9248154.html" target="_blank" rel="noopener">参考链接，里面也有提到区别</a>
；<a href="https://blog.csdn.net/zpalyq110/article/details/79527653" target="_blank" rel="noopener">简单的实例分析</a>
</p>
<p><strong>GBDT：Gradient Boosting Descend Tree</strong></p>
<p>GBDT分类和回归时的基学习器都是<strong>CART分类回归</strong><a href="https://www.jianshu.com/p/b90a9ce05b28" target="_blank" rel="noopener">LINK</a>
树，每轮迭代在上一个基学习器结果的残差至上进行训练，（弱分类器）；</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/20181221075421316.png">
    <img alt="img" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/20181221075421316.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/20181221075421316.png" style="display: block; margin: 0 auto;"
      alt="img"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>这里的残差可以更改为损失函数，然后最后还是会变成对残差的一个拟合，模型的残差实际上也不是这么好弄的，用损失函数的负梯度，来拟合本轮损失的近似值。然后就是从上到下一个个基学习器过去</p>
<p>不同的损失函数针对的是不同的问题（分类回归）</p>
<ul>
<li>分类问题：指数损失函数和对数损失函数</li>
<li>回归问题：均方差损失函数，绝对值损失函数</li>
</ul>
<p>GBDT的正则化：</p>
<ul>
<li>给每个模型乘上一个弱化系数，降低每个模型对拟合损失的贡献</li>
<li>通过按比例来随机抽取样本训练模型，bagging，减少方差但是会增加偏差，可以使用交叉验证</li>
<li>控制CART的复杂度，可以使用剪枝正则化</li>
</ul>
<p>优缺点：</p>
<ul>
<li>灵活，准确率高，使用健壮的损失函数可以处理异常值</li>
<li>难以并行化处理，受限于基学习器之间的依赖关系</li>
</ul>
<p><strong>XGBoost</strong></p>
<p><a href="https://www.jianshu.com/p/b0e147de75e6" target="_blank" rel="noopener">详细讲解XGBoost</a>
；</p>
<p>和残差然后用CART拟合不同，我们是通过SCORE来确定结构，然后通过梯度的值来计算结构中应该有的值， 所以在我们计算完二阶梯度的时候，我们能同步的进行划分和复制，这样，但是还有为为什么要排序后去做，我有点没搞明白</p>
<p>两种方法的区别：</p>
<ul>
<li>正则化防止过拟合，提升泛化能力 L1+L2</li>
<li>还可以使用线性分类器</li>
<li>使用了二阶导数信息来进行对代价函数的优化</li>
<li>采用和随机森林类似的策略，能对数据进行采样，降低过拟合和减少计算</li>
<li>有缩减项，类似weight decay</li>
<li>能计算出缺失值的分裂方向</li>
<li>可并行计算</li>
<li>划分的方式改成了一个Score（根据两阶段梯度数据）</li>
</ul>
<h3 id="svm细节">SVM细节</h3>
<p>在SVM推导部分的后面添加最终的形式以及整理一下KKT条件，通过这些特性对一些问题进行分析</p>
<h4 id="为什么将原问题转化成对偶问题">为什么将原问题转化成对偶问题</h4>
<ol>
<li>对偶问题将原始问题中的不等式约束转为了对偶问题中的等式约束</li>
<li>方便核函数的引入,输入最终会转化从恒一种内积的形式</li>
<li>改变了问题的复杂度。由求特征向量w转化为求比例系数a，在原始问题下，求解的复杂度与样本的维度有关，即w的维度。在对偶问题下，只与样本数量有关。</li>
</ol>
<h4 id="怎么转化到多分类的场景">怎么转化到多分类的场景</h4>
<p>不是逐个二分吗？</p>
<p>hinge损失的多分类形式：https://www.turingtopia.com/article/details/e2492b497a144bf6b3cd1fc62df60bbd</p>
<h4 id="lagrange乘数法对偶问题">Lagrange乘数法，对偶问题</h4>
<p>二次型函数 A是实对称矩阵</p>
<div>
$$ 
f(x)=x^TAx
 $$
</div>
<p>在 $R^N$ 上是凸函数和A是半正定矩阵是充要的关系；</p>
<p>凸规划：目标函数是凸函数，约束空间是凸集</p>
<p>MP是凸规划的条件：满足。。。</p>
<p>为什么凸规划是重要的，因为凸规划的任意局部最优值都是他的整体最优解</p>
<p>凸优化问题Lagrange：</p>
<ul>
<li>引入松弛变量/kkt乘子，将不等式约束转化为等式约束，</li>
<li>引入拉格朗日乘子将等式约束转为无约束优化</li>
</ul>
<p>KKT条件：MP（非线性规划）问题，可微可行点 $x^*$ 是整体最有解的条件
实际上是在凸规划的最优值求解过程中，使用拉格朗日乘数法，其中的不等式约束（&lt;=0）需要满足的条件，其中：</p>
<p>求解Largrange，KT条件的时候我们通常使用互补松紧条件入手来求解（分情况讨论，但是这种时候要考虑分类的完备性来进行求解。）</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210310010553947.png">
    <img alt="image-20210310010553947" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210310010553947.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210310010553947.png" style="display: block; margin: 0 auto;"
      alt="image-20210310010553947"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h4 id="对偶条件的引出">对偶条件的引出</h4>
<p>在线性规划的过程中可以使用对偶问题来进行转化，将求最大转化为求最小值；如果LP问题又最优解，则对偶问题也有最优解，且解相同</p>
<h4 id="svm的具体推导以及核函数">SVM的具体推导以及核函数</h4>
<p>再生希尔伯特空间，</p>
<p>于是我们可以选择多项式核，高斯核，拉普拉斯核之类的来做这个核函数映射</p>
<p><strong>核函数的记忆</strong></p>
<h4 id="相关的面试问题">相关的面试问题</h4>
<p><strong>SVM和LR的联系与区别：</strong></p>
<ul>
<li>
<p>他们都是分类算法，都是监督学习的模型</p>
</li>
<li>
<p>都是判别模型，如果不考虑核函数的话，都是线性分类算法</p>
</li>
<li>
<p>LR采用log损失，SVM采用合页（hinge）损失</p>
</li>
<li>
<p>LR基于概率理论，使用sigmoid和MLE来估计出参数的值；SVM基于几何的边界最大化原理</p>
</li>
<li>
<p>LR对异常值敏感，SVM不</p>
</li>
<li>
<p>对海量数据来说LR效率高，在低纬度的时候LR的准确率高，但是维度上升就被反超</p>
</li>
<li>
<p>处理线性不可分：LR靠特征构造（组合交叉特征，特征离散化），SVM 还可以核函数</p>
</li>
<li>
<p>LR是经验风险最小化，SVM自带结构风险最小化（自带了L2正则项所以）</p>
</li>
</ul>
<p><strong>将数据向SVM求得的超平面进行投影后，是否仍然线性可分？（数学推导，这里的推导我放弃）</strong></p>
<blockquote>
<p>显然不，从支持向量的角度分析，最优的结论必然是两点的中垂线，那么这种情况本身并不是线性可分的，但是如果超平面不是这个中出现的话，那么就不满足SVM求解条件中的最优分界面了。</p>
</blockquote>
<p>70页开始，但是我决定先推导SVM，这一部分的内容再说吧</p>
<p>是否一定存在一组参数使得SVM的训练误差为0？</p>
<p>训练误差为0的SVM分类器一定存在吗？</p>
<p>加入松弛变量的SVM训练误差可以为0吗？</p>
<h3 id="决策树">决策树</h3>
<ul>
<li>
<p>3种分支计算的方法：信息增益，增益率，gini指数</p>
</li>
<li>
<p>预剪枝，后剪枝</p>
</li>
<li>
<p>是否会重复利用连续值或者离散值特征来分树？</p>
<blockquote>
<p>离散特征不行，比如用西瓜的纹理来说：就是有没有了</p>
<p>连续特征可以，阈值切割，我们可以不断的往下细分，比如&lt;100 &lt;50这样。</p>
</blockquote>
</li>
</ul>
<h3 id="pca与lda">PCA与LDA</h3>
<p>优化的目标：最大化投影方差， 在主轴上的投影方差最大，包含更多的信息量（信噪比的概念）。</p>
<p>通过这个思想去设计一个求解过程：中心化（为了使得投影后均值为0），然后求方差，然后推导出最大化问题，然后通过largrange乘数法，推出实际上就是特征值。</p>
<p>LDA投影到的是便于分类的，PCA是方差最大信息量最大的去除冗余的信息维度；无监督有监督</p>
<h3 id="boosting与bagging">Boosting与Bagging</h3>
<p>bagging 解决的是过拟合，boosting解决的是欠拟合的方法</p>
<p>这里需要重新再去温习一下基本的定义</p>
<h3 id="mapmlebayesian">MAP、MLE、Bayesian</h3>
<p><a href="https://blog.csdn.net/u011508640/article/details/72815981/" target="_blank" rel="noopener">https://blog.csdn.net/u011508640/article/details/72815981/</a>
</p>
<p><a href="https://zhuanlan.zhihu.com/p/61593112" target="_blank" rel="noopener">https://zhuanlan.zhihu.com/p/61593112</a>
</p>
<h4 id="从数学意义上和模型上区分">从数学意义上和模型上区分</h4>
<p>显然基于bayesian公式我们可以区分后验和先验，以及使用贝叶斯公式去获得估计的基本依据是啥。（<strong>要看清楚似然的主体是啥，也就是求解的参数是那个</strong>）</p>
<div>
$$ 
P(\theta | D)(后验概率 ) = \frac{P(D|\theta)(似然函数)P(\theta)(先验)}{\sum P(D|\theta)P(\theta)}
 $$
</div>
<p>这里的P实际上可以看成一个概率分布模型，一个推断模型（其中的D和θ一个是模型的数据一个是模型的参数）</p>
<p>前两者将</p>
<p><strong>那么MLE（极大似然）：</strong>（频率学派，假设为定制）</p>
<p>我们把模型参数设置成θ（变量）然后，我们计算当θ等于多少的时候出现D这个数据的概率最大，（这样的话也就会引出我们对大量数据的需求，实际上是一个概率估计模型）</p>
<p><strong>而MAP（最大后验概率）</strong>（和👇一样是贝叶斯学派，θ是随机数）</p>
<p>是贝叶斯估计的一种近似</p>
<p>也就是我们考虑了参数发生或者出现的先验概率以后再进行计算，由于上式的分母P(D)是个确定的值，所以不影响最大化的过程，我们通常再计算的时候将其忽略，然后最大化分子，就是MAP了，在这里这一步的prior是非常重要的，和我们之后的模型估计息息相关。</p>
<p><strong>最后Bayesian估计</strong></p>
<p>其中MAP估计的是后验的最大值，而贝叶斯估计是去近似这个后验函数，基于贝叶斯公式去做这个估计。（去看看数据挖掘中的这部分的题目来帮助理解）</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-321e2cb34e3fcde5c375a1fe24dffc64_r.jpg">
    <img alt="preview" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-321e2cb34e3fcde5c375a1fe24dffc64_r.jpg"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/v2-321e2cb34e3fcde5c375a1fe24dffc64_r.jpg" style="display: block; margin: 0 auto;"
      alt="preview"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<h4 id="朴素贝叶斯问题">朴素贝叶斯问题</h4>
<p>看看数据挖掘中的那个讲稿，就很清楚，实际上就是类关系条件独立假设；</p>
<p>可以使用laplace校准来避免0概率对决策造成影响</p>
<p><strong>那什么是朴素贝叶斯学习呢？</strong></p>
<h3 id="交叉熵-kl散度-信息熵">交叉熵 KL散度 信息熵</h3>
<p><a href="https://blog.csdn.net/b1055077005/article/details/100152102" target="_blank" rel="noopener">https://blog.csdn.net/b1055077005/article/details/100152102</a>
</p>
<h3 id="无监督方法">无监督方法</h3>
<p><strong>K均值聚类</strong>的有优缺点：</p>
<ul>
<li>受离群值影响，通常是局部最优解，类别量级和密度的问题没法解决</li>
<li>需要人工确定k</li>
<li>样本只能被划分到单一的类中</li>
</ul>
<p>如何调优：</p>
<ul>
<li>数据归一化，离群点处理</li>
<li>合理选择K值</li>
<li>核函数</li>
</ul>
<p>证明K means 收敛：和EM算法实际上是一个框架，这里看一下关系</p>
<h4 id="gmm高斯混合模型">GMM：高斯混合模型</h4>
<p>假定不同簇种的样本各自符合不同的高斯分布，这种得到的聚类算法就是高斯混合模型；</p>
<div>
$$ 
P(x) = \sum_{i=1}{K}\pi_iN(x|\mu_i,)
 $$
</div>
<p>核心思想是：每个单独的分模型都是标准高斯模型，我们需要估计高斯分布的双参数，还有一个额外参数（权重或者生成数据的概率），实际上和K均值聚类是一样的操作过程，这里要记得EM。</p>
<p>使用极大似然（很难求解）去寻找均值方差和权重，所以最后使用EM去做</p>
<ul>
<li>随机初始化参数，</li>
<li>E：根据当前参数，计算每个点由某个分模型生成的概率</li>
<li>M：根据概率，来改进每个分模型的均值方差和权重</li>
</ul>
<h4 id="som自组织映射神经网络">SOM：自组织映射神经网络</h4>
<p>nah</p>
<p><strong>聚类算法的评估：</strong></p>
<p>轮廓系数；霍普金斯统计量；R方</p>
<h3 id="数据清洗">数据清洗</h3>
<p>没用到就不说了，在数据挖掘中主要是：缺失数据，错误数据，和噪声数据</p>
<p><strong>错误数据</strong>：分析更改删除和忽略</p>
<p><strong>缺失数据</strong>：忽略，手工，填充（全局常量，属性或者中位数，基于贝叶斯等等方法（这个不提））</p>
<p><strong>噪声数据</strong>：分箱（均值平滑，中值平滑，边界平滑），聚类，回归，人工检查</p>
<h3 id="图像增强策略">图像增强策略</h3>
<p>torchvision.transformers的库里面有很多，还有unbalance_image中有一些经典的unbalance_image的一些策略</p>
<p>还有PIL中的Image.Enhance(这里可能要注意图像维度的转换)</p>
<p>1、对比度：白色画面(最亮时)下的亮度除以黑色画面(最暗时)下的亮度；</p>
<p>2、色彩饱和度：：彩度除以明度，指色彩的鲜艳程度，也称色彩的纯度；</p>
<p>3、色调：向负方向调节会显现红色，正方向调节则增加黄色。适合对肤色对象进行微调；</p>
<p>4、锐度：是反映图像平面清晰度和图像边缘锐利程度的一个指标。</p>
<p>MixUp的操作实际上就不要在赘述了，而Sharpen的操作实际上就是对分子分母都做一个1/T的乘方的这样一个锐化的操作，突出显著的样例，这样能够使得：？（需要加强记忆）</p>
<h3 id="评估模块">评估模块</h3>
<h4 id="rocprf1">ROC、PR、F1</h4>
<p>PR曲线就比较清楚是根据Precision和recall区划分的，然后根据判定为正负样本的阈值去区分这个曲线的情况。</p>
<p>ROC曲线是根据 TPR和FPR真阳性率（正样本中有多少被判定为真）和伪阳性率（负样本中有多少被判定为真），依据score的阈值来绘制曲线</p>
<blockquote>
<p>AUC越大，说明分类器越可能把真正的正样本放在前面</p>
</blockquote>
<p>还有F1，是综合反应一个排序模型的性能(调和平均值)：</p>
<div>
$$ 
F1 = \frac {2*precision * recall}{precision + recall}
 $$
</div>
<p>ROC比起PR来说，对于正负样本数据量的分布比较不敏感，所以在这种数据不均衡的大数据场景，ROC更合适，更广泛。如果是针对特定数据集上的表现的话实际上PR曲线的话能更直观的反应性能</p>
<h4 id="rmse">RMSE</h4>
<p>离群点可能导致效果一直很差，可以用归一化的百分比来看</p>
<h4 id="余弦相似度">余弦相似度</h4>
<p>实际上就是将问题从距离转换到了角度上，用1-cos(A,B)表示余弦距离，实际上这种距离比起欧氏距离来说，能够适应更高的维度，比较相对差异的时候我们可以考虑用余弦相似度来衡量</p>
<p>不满足三角不等式：等腰直角三角形</p>
<p>在机器学习领域，还有kl距离，相对熵，也能衡量两个分布之间的距离，但是也不满足对称性和三角不等式</p>
<h3 id="训练集和测试集的划分机制">训练集和测试集的划分机制</h3>
<ul>
<li>
<p>K次交叉验证法；</p>
<blockquote>
<p>首先描述一下什么是k次交叉验证，k次交叉验证的作用是：评估模型的预测性能，训练好的模型再新数据上的表现，在一定程度上减少过拟合，从有限数据中获取尽可能多的有效信息，使得模型对于数据的划分不那么敏感</p>
</blockquote>
</li>
<li>
<p>Handout检验：实际上就是7：3的随机划分的方式；其中还有留一划分的策略；</p>
</li>
<li>
<p>自助法（bootstrap）：有放回的随机抽样，总数为n的集合，抽样n次作为训练集，剩下的没有被抽样出来的数据作为测试集，这就是自助法的验证过程</p>
<ul>
<li>当抽样次数趋向于无穷的时候，有多少数据没有被选择过， $(1-\frac{1}{n})^n$ 取极限，根据重要极限 $(1+\frac{1}{n})^n$ 的极限是e，可以推得大概是1/e的概率没被选中，也就是大概百分之36%， （59页）</li>
</ul>
</li>
</ul>
<h2 id="语言部分">语言部分</h2>
<h3 id="python部分">Python部分</h3>
<h4 id="深拷贝浅拷贝">深拷贝浅拷贝</h4>
<p>概念上是一致的，但是具体实现深拷贝上，是不一样的，python 应该是自带的.copy函数</p>
<p><a href="https://www.jianshu.com/p/a71c09798123" target="_blank" rel="noopener">https://www.jianshu.com/p/a71c09798123</a>
)</p>
<h4 id="修饰符的作用">修饰符的作用</h4>
<p>修饰符的作用python函数修饰符@的作用是为现有函数增加额外的功能，常用于插入日志、性能测试、事务处理等等。</p>
<p>实际上就是讲函数作为作为输入参数，然后对函数进行包装，在执行函数之前或者之后增加一些操作，通常用来指示函数执行进程，也可以用来添加数据预处理等等</p>
<p><a href="https://www.cnblogs.com/gdjlc/p/11182441.html" target="_blank" rel="noopener">LINK REFERENCE</a>
</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">log</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">wrapper</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;log开始 ...&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">func</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;log结束 ...&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">wrapper</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl"><span class="nd">@log</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">test</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;test ..&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">test</span><span class="p">()</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><h4 id="多线程处理">多线程处理</h4>
<h5 id="一些基本的概念">一些基本的概念：</h5>
<blockquote>
<p>每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行，必须依存在应用程序中，由应用程序提供多个线程执行控制。</p>
<p>每个线程都有他自己的一组CPU寄存器，称为线程的上下文，该上下文反映了线程上次运行该线程的CPU寄存器的状态。</p>
<p>指令指针和堆栈指针寄存器是线程上下文中两个最重要的寄存器，线程总是在进程得到上下文中运行的，这些地址都用于标志拥有线程的进程地址空间中的内存。</p>
<ul>
<li>线程可以被抢占（中断）。</li>
<li>在其他线程正在运行时，线程可以暂时搁置（也称为睡眠） &ndash; 这就是线程的退让。</li>
</ul>
</blockquote>
<h5 id="使用threading作为线程处理模块"><strong>使用threading作为线程处理模块：</strong></h5>
<p><code>run</code> <code>start</code> <code>join([timr])</code>：等待至线程终止；<code>isAlive()</code> <code>getName()</code> <code>setName()</code></p>
<p><code>append()</code>:添加到线程列表，使用for i in threads: i.join() 来等待所有线程完成。</p>
<ol>
<li>首先通过继承threading.thread创建子类，实现run操作；</li>
<li>实例化之后使用start启动进程；</li>
</ol>
<h5 id="线程同步lock">线程同步（Lock）</h5>
<p><code>Lock</code>和<code>Rlock</code> 都有相应<code>acquire</code>和<code>release</code>，</p>
<p>防止多个线程同时对某个数据进行修改，就需要对多个线程进行同步；</p>
<h5 id="python-中多线程和多进程的区别">Python 中多线程和多进程的区别</h5>
<p>这一点还是需要补充，好像是使用什么来着</p>
<p>主要从进程和线程本身的区别来谈，然后Python中的多线程是收到了Cpython的GIL约束的，所以稍微有点鸡肋，可能还是要用多进程去了解</p>
<p>[参考链接](</p>
<h4 id="文件io部分">文件IO部分</h4>
<h5 id="文件处理">文件处理：</h5>
<p>读取键盘输入：<code>a = input('请输入：')</code>；</p>
<p>打开和关闭文件：<code>open()</code>，一般需要按照指定的格式打开一个文件才能对其进行修改或者读取。</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>python</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">fo</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&#34;foo.ext&#34;</span><span class="p">,</span><span class="s2">&#34;w&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">fo</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 相应的文件的读写实际上应该是</span>
</span></span><span class="line"><span class="cl"><span class="n">fo</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&#34;dadsad&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">res</span> <span class="o">=</span> <span class="n">fo</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 使用tell 和seek输出和定位当前的文件位置，</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 实际上经常和with命令一起使用</span>
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">path</span><span class="p">,</span><span class="s2">&#34;w&#34;</span><span class="p">,</span><span class="n">encoding</span><span class="o">=</span><span class="s1">&#39;utf-8&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span> <span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># record the dir name (depth=1) </span>
</span></span><span class="line"><span class="cl">    <span class="n">f</span><span class="o">.</span><span class="n">writelines</span><span class="p">(</span><span class="n">authorres</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># record all the video</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">element</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">element</span><span class="p">)</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>补充说明： 这里<a href="http://www.coolpython.net/python_senior/senior_feature/with.html" target="_blank" rel="noopener">with语句的解析</a>
</p>
<h5 id="os命令">OS命令</h5>
<p>chmod，chdir，chown，mkdir，path（一系列常用操作，exist之类的），getcwd（返回当前工作区），listdir（返回文件夹包含的文件或者文件夹的列表）</p>
<h3 id="c部分">C++部分</h3>
<p>实际上c++对于编写的顺序是有上下关系的，如果我们定义的时候遇到了一些上面和下面的差别的时候，我们可以考虑在上面先进行declaration，在后面在具体的进行definition。</p>
<h4 id="文件操作">文件操作：</h4>
<h5 id="基本读写">基本读写</h5>
<p>写文件步骤如下：</p>
<ol>
<li>
<p>包含头文件  <code>#include &lt;fstream\&gt;</code></p>
</li>
<li>
<p>创建流对象  <code>ofstream ofs;</code></p>
</li>
<li>
<p>打开文件<code>ofs.open(&quot;文件路径&quot;,打开方式);</code></p>
</li>
<li>
<p>写数据<code>ofs &lt;&lt; &quot;写入的数据&quot;</code>;</p>
</li>
<li>
<p>关闭文件<code>ofs.close()</code>;</p>
</li>
</ol>
<p>读文件的操作步骤如下</p>
<ol>
<li>
<p>包含头文件   #include &lt;fstream&gt;</p>
</li>
<li>
<p>创建流对象  ifstream ifs;</p>
</li>
<li>
<p>打开文件并判断文件是否打开成功 ifs.open(&ldquo;文件路径&rdquo;,打开方式);</p>
</li>
<li>
<p>读数据 四种方式读取</p>
</li>
<li>
<p>关闭文件 ifs.close();</p>
</li>
</ol>
<h5 id="处理二进制文件">处理二进制文件</h5>
<p>二进制方式写文件主要利用流对象调用成员函数write</p>
<p>函数原型 ：<code>ostream&amp; write(const char * buffer,int len);</code></p>
<p>参数解释：字符指针buffer指向内存中一段存储空间。len是读写的字节数</p>
<p>打开方式要指定为 ios::binary；</p>
<p>二进制方式读文件主要利用流对象调用成员函数read</p>
<p>函数原型：<code>istream&amp; read(char *buffer,int len);</code></p>
<p>参数解释：字符指针buffer指向内存中一段存储空间。len是读写的字节数</p>
<h4 id="预编译头">预编译头</h4>
<p>首先介绍的是如何防止在重复的include&lt;head.h&gt;的时候,不会导致重复的定义和include的方式，以及其中的区别</p>
<p>#pragma once：自定义包含了这种情况的时候，依赖于不会将同一个文件多次编译，这个方式<strong>没办法保证内容相同的不同名文件</strong>被重复的编译，针对的是文件。</p>
<p><code> #ifndef ：依赖于宏名称不能冲突，这个能保证内容相同的不同文件不小心被同时包含，实际上是一个预编译的条件语句</code></p>
<p>首先介绍一下写法：</p>
<div class="code-block">
    <div class="code-title" onclick="toggleCode(this)">
        
        <span class="code-block-open"><ion-icon name="chevron-down-outline"></ion-icon></span>
        <span class="code-block-close"><ion-icon name="chevron-forward-outline"></ion-icon></ion-icon></span>
        <span>cpp</span>
    </div>
    <div class="code-content">
        
        <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="err">基本的逻辑也就是当我们第一次执行的时候，就会预先定义到这一块，这样到时候就不会导致相应部分的代码被重复的执行或者定义</span>
</span></span><span class="line"><span class="cl"><span class="cp">#ifndef _code_block
</span></span></span><span class="line"><span class="cl"><span class="cp">#define _code_block
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="c1">// code here
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="cp">#endif</span></span></span></code></pre></div>
    </div>
</div>

<script>
function toggleCode(element) {
    const codeContent = element.nextElementSibling;
    if (codeContent.style.display === "none" || codeContent.style.display === "") {
        codeContent.style.display = "block"; 
        codeContent.parentNode.classList.remove("code-has-hidden-child");
    } else {
        codeContent.style.display = "none"; 
        codeContent.parentNode.classList.add("code-has-hidden-child");
    }
}
</script><p>在自己编写的时候需要注意不能重复使用宏名（<code>_code_block</code>），不然可能会出现以外的其他地方的代码没有被执行。</p>
<h4 id="多线程">多线程</h4>
<p>mutex互斥锁</p>
<h4 id="内存分区模型">内存分区模型</h4>
<p>主要将内存分为四个区域:</p>
<ul>
<li>
<p>代码区：存放函数的二进制代码，由操作系统进行管理</p>
<blockquote>
<p>程序运行前进行分配</p>
<p>存放CPU执行的机器指令，具体而言代码区是共享的和只读的</p>
</blockquote>
</li>
<li>
<p>全局区：存放全局变量、静态变量和常量</p>
<blockquote>
<p>这部分空间应该是在预编译的时候事先分配的</p>
<p>该部分的数据再程序结束后由操作系统释放</p>
</blockquote>
</li>
<li>
<p>栈区：由编译器制动分配和释放，存放函数的参数值，局部变量等</p>
</li>
<li>
<p>堆区：由程序员分配和释放，如果程序员不释放，程序结束后由操作系统回收；</p>
</li>
</ul>
<p>（类内的存储特点）：</p>
<p>在c++中，类内的成员变量和成员函数分开存储，只有非静态的成员变量才属于类的对象上的存储。（函数也是不占对象空间的，所有的函数共享一个函数实例）</p>
<p>（static）静态成员函数在编译阶段分配内存，类内声明类外初始化，所有的对象共享同一份数据；</p>
<h4 id="类">类：</h4>
<h5 id="this指针">THIS指针</h5>
<p>指向的是，当前调用的这个 <strong>对象</strong>；</p>
<h5 id="友元friend">友元friend：</h5>
<p>通过friend关键词告诉编译器其他的可以访问类中私有内容的东西；</p>
<p>友元可以是：</p>
<ul>
<li>函数</li>
<li>类</li>
<li>其他类别的成员函数</li>
</ul>
<h5 id="继承">继承</h5>
<p><strong>构造函数顺序</strong></p>
<p>继承的时候首先调用父类的构造函数，在构造子类的构造函数，析构是反向的。</p>
<p><strong>几种继承方式</strong></p>
<p>注意区分继承方式面临的主体，也就是说：</p>
<ul>
<li>派生类能访问的元素实际上都是除了私有类都能访问</li>
<li>区别在于我们是否能通过派生类的实例对基类的变量进行访问，这里的继承方式就代表着这些变量在被继承之后的状态，是私有的保护的，还是公共的</li>
</ul>
<p><strong>父子的成员同名</strong></p>
<p>无论是不是静态，都是：</p>
<ul>
<li>访问子类同名成员   直接访问即可</li>
<li>访问父类同名成员   需要加作用域</li>
</ul>
<h4 id="多态">多态</h4>
<p><strong>多态是C++面向对象三大特性之一</strong></p>
<p>多态分为两类</p>
<ul>
<li>静态多态: 函数重载 和 运算符重载属于静态多态，复用函数名</li>
<li>动态多态: 派生类和虚函数实现运行时多态</li>
</ul>
<p>静态多态和动态多态区别：</p>
<ul>
<li>静态多态的函数地址早绑定  -  编译阶段确定函数地址</li>
<li>动态多态的函数地址晚绑定  -  运行阶段确定函数地址</li>
</ul>
<p>多态使用时，如果子类中有属性开辟到堆区，那么父类指针在释放时无法调用到子类的析构代码</p>
<p>解决方式：将父类中的析构函数改为<strong>虚析构</strong>或者<strong>纯虚析构</strong></p>
<p>​	1. 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象</p>
<p>​	2. 如果子类中没有堆区数据，可以不写为虚析构或纯虚析构</p>
<pre><code>3. 拥有纯虚析构函数的类也属于抽象类
</code></pre>
<h4 id="常用stl函数">常用STL函数</h4>
<ul>
<li>for_each：遍历容器</li>
<li>transform：搬运容器中的数据到另一个容器中</li>
<li>accumulate：计算容器的元素综合</li>
<li>fill：向容器中添加元素</li>
<li>replace_if</li>
<li>find_if</li>
<li>set_union：求两个容器的并集</li>
<li>set_intersection：求两个容器的交集</li>
</ul>
<h3 id="通用部分">通用部分：</h3>
<h4 id="深拷贝和浅拷贝的概念">深拷贝和浅拷贝的概念：</h4>
<p>浅拷贝：简单的赋值拷贝操作</p>
<p>深拷贝：在堆区重新申请空间，进行拷贝操作</p>
<h4 id="同步与异步">同步与异步</h4>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210319155434936.png">
    <img alt="image-20210319155434936" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210319155434936.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210319155434936.png" style="display: block; margin: 0 auto;"
      alt="image-20210319155434936"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>

  </div>
</div>

<script>
    


function sanitizeContent(content) {
    
    return content.replace(/[\x00-\x1F\x7F]/g, '').trim(); 
}

function encryptContent(password, content) {
    const key = CryptoJS.MD5(password).toString();
    const iv = key.substring(16); 
    const paddedContent = padContent(content);
    const encrypted = CryptoJS.AES.encrypt(paddedContent, CryptoJS.enc.Utf8.parse(key), {
        iv: CryptoJS.enc.Utf8.parse(iv),
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
}

function padContent(content) {
    const blockSize = 32; 
    const padlen = blockSize - (content.length % blockSize);
    
    
    return content;
}

function processEncryptedBlocks() {
    const blocks = document.querySelectorAll('.hugo-encryptor-cipher-text');
    blocks.forEach(block => {
        const password = block.getAttribute('data-password');
        const content = block.innerHTML.trim(); 
        const sanitizedContent = sanitizeContent(content); 
        const encryptedContent = encryptContent(password, sanitizedContent);
        block.innerHTML = encryptedContent;
        block.removeAttribute('data-password');
    });

    
    const script = document.createElement('script');
    script.src = '/js/decrypt.js';
    document.body.appendChild(script);
}


document.addEventListener('DOMContentLoaded', processEncryptedBlocks);
</script>
]]></content:encoded>
    </item>
    <item>
      <title>Involution</title>
      <link>https://aikenh.cn/posts/involution/</link>
      <pubDate>Thu, 08 Apr 2021 13:12:15 +0000</pubDate>
      <guid>https://aikenh.cn/posts/involution/</guid>
      <description>Inverting the Inherence of Convolution for Visual Recognition</description>
      <content:encoded><![CDATA[<p>@Aiken 2021-4-8</p>
<p><a href="https://mp.weixin.qq.com/s/UmumqhZW7Aqk6s8X1Aj7aA" target="_blank" rel="noopener">Ariticle </a>
；<a href="https://arxiv.org/abs/2103.06255" target="_blank" rel="noopener">Paper</a>
；<a href="https://github.com/d-li14/involution" target="_blank" rel="noopener">:star:Code；</a>
 <a href="https://zhuanlan.zhihu.com/p/357408252" target="_blank" rel="noopener">ZHIHU</a>
</p>
<h2 id="intro-引子">Intro 引子</h2>
<p>提出了一种新的神经网络算子（operator或op）称为involution，它比convolution更轻量更高效，形式上比self-attention更加简洁，可以用在各种视觉任务的模型上取得精度和效率的双重提升。</p>
<p>通过involution的结构设计，我们能够以统一的视角来理解经典的卷积操作和近来流行的自注意力操作。</p>
<h2 id="基本思想">基本思想</h2>
<p>将传统Convolution Kernel 的两个基本特性：</p>
<ul>
<li>**空间不变性：**在同个通道的HW上共享3*3的卷积系数，参数共享；</li>
<li>**通道特异性：**在每个通道上有特异的卷积核，最终使用1*1 like的方式来进行通道间的整合</li>
</ul>
<p>反对称的修改成：</p>
<ul>
<li><strong>空间特异性：</strong> 对每个Feature有对应size  $H·W·K·K·G | G&laquo;C$  的kernel，特异性的对不同图像的不同部分进行处理
<ul>
<li>G表示Involution操作的分组数，如果需要下采样，就需要接步长为2的平均池化层，最终可以得到，实际上是一个分组卷积的方式，也就是说，我们K个一组的共享一个Kernel。用G去切分C，最终组合起来</li>
</ul>
</li>
<li>**通道不变性：**对每个通道之间共享这样的kernel，然后做简单的线性整合，对每个不同的channel有相同的处理方式。</li>
</ul>
<p>传统的卷积基于邻域相关性的思想，同时旨在同一个channel中用单一的角度去分析特征，所以有空间不变性核通道特异性的这两个特征。</p>
<p>而Involution实际上更像是Self-Attention这种思路，通过Whole-Size的Kernel，执行一个特异性处理？</p>
<h2 id="要点分析">要点分析</h2>
<p>这一部分主要介绍一些实现上的技术/理论要点：</p>
<h3 id="生成featuremap对应size的kernel"><strong>生成FeatureMap对应Size的Kernel</strong></h3>
<p>通用的公式如下，我们可以自定义对应的Kernel生成Function，这是算法的开放性和潜力所在。</p>
<div>
$$ 
\mathbf{H}_{i,j} = \phi(\mathbf{X}_{\Psi_{i,j}}) \\
\Psi_{i,j} 是邻域的一个index集合，\mathbf{X}_{\Psi_{i,j}}是包含i,j的邻域的一个patch
 $$
</div>
<p>其中可能会包含一些线性变换和通道缩减之类的变换，一种简单的实例化可以由下图来理解。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210409110945686.png">
    <img alt="image-20210409110945686" loading="lazy" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210409110945686.png"class="responsive-image" src="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210409110945686.png" style="display: block; margin: 0 auto;"
      alt="image-20210409110945686"  />
  </a>
</div>


<script>
  document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll(".responsive-image");
      var maxHeight = window.innerHeight / 2.5;
      images.forEach(function(image) {
          image.style.maxHeight = maxHeight + "px";
      });
  });
</script>
</p>
<p>对某个index，首先转化生成对应的 $K^2$ ，对应的Value，然后通过加权整合得到最终的OutputValue， Channel 数的放射就又我们的对应生成的Kernel数去控制。</p>
<p>
<div class="post-img-view">
  <a data-fancybox="gallery" href="https://raw.githubusercontent.com/AikenH/md-image/master/img/image-20210409111251815.png">
    <img alt="image-20210409111251815" loading="lazy" src="http